.codecov.yml .editorconfig .gitattributes .gitignore .gitlab-ci.yml LICENSE.TXT README.md docsrc/alias_declaration.md docsrc/attribute.md docsrc/class_declaration.md docsrc/cross_compilation.md docsrc/declaration.md docsrc/enum_declaration.md docsrc/expression_alias.md docsrc/expressions.md docsrc/file_extensions.md docsrc/function_declaration.md docsrc/generate.d docsrc/generate.sh docsrc/generics.md docsrc/import_declaration.md docsrc/index.md docsrc/lexical_aspects.md docsrc/overload_declaration.md docsrc/post_expressions.md docsrc/pre_expressions.md docsrc/presentation.md docsrc/primary_expressions.md docsrc/protection_declaration.md docsrc/statements.md docsrc/struct_declaration.md docsrc/style.css docsrc/styx_kde_syntax.xml docsrc/type.md docsrc/unary_expressions.md docsrc/unit_declaration.md docsrc/variable_declaration.md docsrc/version_block_declaration.md get-previous.sh library/rtl.sx makefile misc/d/src/llvm/analysis.d misc/d/src/llvm/bit_reader.d misc/d/src/llvm/bit_writer.d misc/d/src/llvm/comdat.d misc/d/src/llvm/core.d misc/d/src/llvm/data_types.d misc/d/src/llvm/debug_info.d misc/d/src/llvm/disassembler.d misc/d/src/llvm/disassembler_types.d misc/d/src/llvm/error.d misc/d/src/llvm/error_handling.d misc/d/src/llvm/execution_engine.d misc/d/src/llvm/extern_c.d misc/d/src/llvm/initialization.d misc/d/src/llvm/ir_reader.d misc/d/src/llvm/link_time_optimizer.d misc/d/src/llvm/linker.d misc/d/src/llvm/lto.d misc/d/src/llvm/object.d misc/d/src/llvm/orc.d misc/d/src/llvm/orcbindings.d misc/d/src/llvm/remarks.d misc/d/src/llvm/support.d misc/d/src/llvm/target.d misc/d/src/llvm/target_machine.d misc/d/src/llvm/transforms/aggressive_inst_combine.d misc/d/src/llvm/transforms/coroutines.d misc/d/src/llvm/transforms/inst_combine.d misc/d/src/llvm/transforms/ipo.d misc/d/src/llvm/transforms/pass_manager_builder.d misc/d/src/llvm/transforms/scalar.d misc/d/src/llvm/transforms/utils.d misc/d/src/llvm/transforms/vectorize.d misc/d/src/llvm/types.d misc/dockerfiles/pages-f33/Dockerfile misc/dockerfiles/pages-f33/build.sh misc/dockerfiles/test-image.fedora.x86_64/Dockerfile misc/dockerfiles/test-image.fedora.x86_64/build.sh misc/dockerfiles/test-image.ubuntu.x86_64/Dockerfile misc/dockerfiles/test-image.ubuntu.x86_64/build.sh misc/grammar/README.md misc/grammar/dub.json misc/grammar/formal/peg.txt misc/grammar/src/app.d misc/local_escapes_design.sx misc/logo/logo.png misc/logo/logo.svg misc/matchex/README.md misc/matchex/makefile misc/matchex/src/matchex.sx misc/matchex/tests/main.sx misc/matchex/tests/test1.sh misc/matchex/tests/test2.sh misc/matchex/tests/test3.sh misc/matchex/tests/test4.sh misc/string_switch_lut.sx release.sh src/algorithms.sx src/driver.sx src/styx/ast/base.sx src/styx/ast/copier.sx src/styx/ast/declarations.sx src/styx/ast/expressions.sx src/styx/ast/formatter.sx src/styx/ast/statements.sx src/styx/ast/types.sx src/styx/ast/visitor.sx src/styx/backend.sx src/styx/backend/irgen.sx src/styx/backend/link.sx src/styx/backend/llvm.sx src/styx/lexer.sx src/styx/lint.sx src/styx/parser.sx src/styx/position.sx src/styx/sar.sx src/styx/scope.sx src/styx/semantic.sx src/styx/semantic/bodies.sx src/styx/semantic/declarations.sx src/styx/semantic/deprecations.sx src/styx/semantic/evaluate.sx src/styx/semantic/expressions.sx src/styx/semantic/imports.sx src/styx/semantic/memulator.sx src/styx/semantic/protection.sx src/styx/semantic/statements.sx src/styx/semantic/symbolize.sx src/styx/semantic/types.sx src/styx/session.sx src/styx/string_switch.sx src/styx/symbol.sx src/styx/token.sx src/system.sx styx.dgrp test.sh tests/backend.yml tests/backend/ab.sar tests/backend/abstract_call.sx tests/backend/alias_write_bug.sx tests/backend/andand_oror.sx tests/backend/array_literals_as_lvalue.sx tests/backend/asm_exp.sx tests/backend/at_param.sx tests/backend/at_return.sx tests/backend/at_unittest.sx tests/backend/auto_counter.sx tests/backend/auto_func.sx tests/backend/auto_nested_condexp.sar tests/backend/bad_intrinsic_name.sx tests/backend/bitset.sx tests/backend/breaks_in_cond.sx tests/backend/bug_missing_this.sx tests/backend/builtin_enumset.sx tests/backend/builtin_rca.sx tests/backend/builtin_types_ctors.sx tests/backend/chained_assign.sx tests/backend/class_compare_bug.sx tests/backend/cmp_operand_promotion.sx tests/backend/common_class_ptr_type.sx tests/backend/cond_exp.sx tests/backend/continue_on.sx tests/backend/count_chars.sx tests/backend/cover_assertz_gcov.sx tests/backend/cover_empty_switch_matches.sx tests/backend/cover_link_error.sx tests/backend/cover_stderr_for_run.sx tests/backend/cover_verifier_failure.sx tests/backend/ctor.sx tests/backend/dtor_override_bug.sx tests/backend/dyn_array.sx tests/backend/dyn_casts.sx tests/backend/early_return.sx tests/backend/empty_unittest_array.sx tests/backend/enum_fixes.sx tests/backend/enum_foreach.sx tests/backend/exp_aliases.sx tests/backend/explicit_this_param.sx tests/backend/expressions.sx tests/backend/external_local_member_func.sx tests/backend/final_devirtualized_calls.sx tests/backend/fix_assertz_noasserts.sx tests/backend/fix_echo_test_virt_index.sx tests/backend/fix_generic_reemit/app.sx tests/backend/fix_generic_reemit/library.sx tests/backend/fix_generic_reemit/test.sh tests/backend/fix_null_then_block.sx tests/backend/fix_stack_allocated_class_casts.sx tests/backend/fix_super_call_inf_loop.sx tests/backend/fix_unused_class_crash.sx tests/backend/fix_void_return.sx tests/backend/foreach.sx tests/backend/foreach_over_aggregate.sx tests/backend/function_pointers.sx tests/backend/gen_dwarf.sx tests/backend/gen_in_right_module.sar tests/backend/generated_aggregate_dtors.sx tests/backend/generics.sx tests/backend/global_string_crash.sx tests/backend/hello_world.sx tests/backend/if_else_return.sx tests/backend/implicit_check_assert.sx tests/backend/implicit_overload_set.sx tests/backend/implicit_struct_deref.sx tests/backend/implicit_this.sx tests/backend/import_package_logic.sar tests/backend/imported_intrinsic_bug.sar tests/backend/inherited_layout_backend_cycle.sx tests/backend/ir_right_module.sar tests/backend/issue197.sx tests/backend/issue204.sx tests/backend/issue220.sx tests/backend/issue221.sx tests/backend/issue226.sx tests/backend/issue231.sx tests/backend/issue232.sx tests/backend/issue238.sx tests/backend/issue239.sar tests/backend/issue240.sar tests/backend/issue244.sar tests/backend/issue263.sar tests/backend/issue264.sx tests/backend/issue265.sx tests/backend/issue280.sx tests/backend/issue295.sar tests/backend/issue329.sx tests/backend/issue339.sx tests/backend/issue34.sx tests/backend/issue347.sx tests/backend/issue408.sx tests/backend/issue476.sx tests/backend/issue533.sx tests/backend/issue566/sn_a.sx tests/backend/issue566/sn_b.sx tests/backend/keywords.sx tests/backend/lambda_exp.sx tests/backend/link_obj_import/app.sx tests/backend/link_obj_import/imported.sx tests/backend/link_obj_import/test.sh tests/backend/llvm_intrinsics.sx tests/backend/loop_alloca.sx tests/backend/lvalue_transition.sx tests/backend/m32.sx tests/backend/member_index_bug.sar tests/backend/min_max_props.sx tests/backend/misc_coverage.sx tests/backend/missing_copy_to_local.sx tests/backend/more_implicit_conv.sx tests/backend/nested_funcs.sx tests/backend/nested_sw.sx tests/backend/new_delete.sx tests/backend/num_trunc_ext.sx tests/backend/operator_overload.sx tests/backend/opt_access.sx tests/backend/opt_assign.sx tests/backend/opt_break_cont_lbl.sx tests/backend/out_of_order_inheritance.sx tests/backend/over_cast.sx tests/backend/overload_base.sar tests/backend/overload_identexp.sx tests/backend/overloads.sx tests/backend/pointer_set.sx tests/backend/position.sx tests/backend/program_name_len.sx tests/backend/pure_asm.sx tests/backend/rca_elem_dtor.sx tests/backend/read_atomic_struct_members_to_globals/d_side.d tests/backend/read_atomic_struct_members_to_globals/styx_side.sx tests/backend/read_atomic_struct_members_to_globals/test.sh tests/backend/read_sarray_in_globals/d_side.d tests/backend/read_sarray_in_globals/styx_side.sx tests/backend/read_sarray_in_globals/test.sh tests/backend/relax_virt_func_ptr.sx tests/backend/return_auto_null.sx tests/backend/rod_picks.sx tests/backend/rtl_class_opover.sx tests/backend/runtime_errors/abstract_call.sx tests/backend/runtime_errors/assert_failure.sx tests/backend/runtime_errors/assertz_nomsg.sx tests/backend/runtime_errors/assertz_return.sx tests/backend/runtime_errors/bounds_check.sx tests/backend/runtime_errors/dotvar1.sx tests/backend/runtime_errors/dotvar2.sx tests/backend/runtime_errors/sliceass_bounds_check.sx tests/backend/runtime_errors/this_calls.sx tests/backend/runtime_errors/uncovered_switch_on.sx tests/backend/selective_import.sar tests/backend/separate_compilation_generics/a.sx tests/backend/separate_compilation_generics/b.sx tests/backend/size_prop.sx tests/backend/slice_elem_ass.sx tests/backend/slice_exp.sx tests/backend/static_ctors.sx tests/backend/static_members.sx tests/backend/static_slices.sx tests/backend/string_ptr_bug.sx tests/backend/string_switches.sx tests/backend/stringof_prop.sx tests/backend/stringof_ufcs_bug.sx tests/backend/struct_array_cmp.sx tests/backend/struct_param_by_value.sx tests/backend/structs_mutually_dependent.sar tests/backend/switches.sx tests/backend/system.sx tests/backend/temp_class_test.sx tests/backend/test_at_return_var.sx tests/backend/test_call_parameters.sx tests/backend/test_lazy_imports/a.sx tests/backend/test_lazy_imports/a/b.sx tests/backend/test_lazy_imports/app.sx tests/backend/test_reverse.sx tests/backend/test_visitor.sar tests/backend/test_visitor_single_unit.sx tests/backend/this_call.sx tests/backend/tidass.sx tests/backend/tidexp_managed_locals.sx tests/backend/token.sx tests/backend/tuples.sx tests/backend/typevar.sx tests/backend/u8_pointer_inc/d_side.d tests/backend/u8_pointer_inc/styx_side.sx tests/backend/u8_pointer_inc/test.sh tests/backend/ufcs.sx tests/backend/unions.sx tests/backend/va_start_end.sx tests/backend/var_parameter.sx tests/backend/var_return_not_stripped.sx tests/backend/variadic.sx tests/backend/variadic1_reg.sx tests/backend/various.sx tests/backend/various_cov.sx tests/backend/virtual_ctor_dtor.sx tests/backend/vtbl_corrupt.sx tests/backend/write_const_to_globals/d_side.d tests/backend/write_const_to_globals/styx_side.sx tests/backend/write_const_to_globals/test.sh tests/compile/array_literals.sx tests/compile/assertz.sx tests/compile/auto_enum.sx tests/compile/auto_type.sar tests/compile/bool_sw.sx tests/compile/break_after_exp_crash.sx tests/compile/bug_not_ufcs.sx tests/compile/declarations.sx tests/compile/echo.sx tests/compile/enum_name_inference.sx tests/compile/enumset.sx tests/compile/escape_used.sx tests/compile/eval.sx tests/compile/explicit_cast_but_could_be_implicit.sx tests/compile/foreach_bce.sx tests/compile/foreach_var.sx tests/compile/if_func_alias.sx tests/compile/imp_conv.sx tests/compile/import_as_var_decl.sar tests/compile/import_list_bug.sar tests/compile/importable/importable_a.sx tests/compile/importable/importable_b.sx tests/compile/importer.sx tests/compile/importer_versioned.sx tests/compile/imports_in_generic.sar tests/compile/inherited_size.sar tests/compile/issue117.sx tests/compile/issue219.sx tests/compile/issue230.sx tests/compile/issue256.sx tests/compile/issue503.sar tests/compile/issue526.sar tests/compile/issue526_2.sar tests/compile/issue532.sar tests/compile/issue535.sar tests/compile/issue571.sx tests/compile/linter.sx tests/compile/local_import_scope.sar tests/compile/local_type_visibility.sx tests/compile/lookup_in_alias.sar tests/compile/member_solve.sx tests/compile/misc_symbolsearch_cov.sar tests/compile/protected_member.sar tests/compile/qual_user.sar tests/compile/run_args.sx tests/compile/same_unit_alias.sx tests/compile/scoped_statement_relative_var.sx tests/compile/simple_main.sx tests/compile/simple_sar.sar tests/compile/solve_fullqual_from_import_alias.sar tests/compile/test_typeexp_no_colon.sx tests/compile/type_in_ident_chain.sx tests/compile/typefromimport.sx tests/compile/typetoimport.sx tests/compile/ufcs.sx tests/compile/ufcs_breakage.sx tests/compile/union_member_func_crash.sx tests/compile/unused_imports.sar tests/compile/with_expressions.sx tests/cover/ast_printer.sx tests/cover/cover_parse_err.sx tests/cover/cover_wdisabled.sx tests/cover/cover_werror.sx tests/cover/invalid_ext.sx tests/cover/non_existant.sx tests/cover/option_error.sx tests/cover/same_unit_decl.sx tests/cover/show_help.sx tests/cover/unit_dot_symbolize.sar tests/cover/until.sx tests/fail/alias_bypass_prot.sx tests/fail/alias_other_unit_no_import.sar tests/fail/arraysem.sx tests/fail/ass_type_mods.sx tests/fail/auto_no_init.sx tests/fail/bad_at_overload.sx tests/fail/bad_attribs.sx tests/fail/bad_auto.sx tests/fail/bad_circular_things.sx tests/fail/bad_control_flow.sx tests/fail/bad_ctor_dtor.sx tests/fail/bad_enum.sx tests/fail/bad_enumset.sx tests/fail/bad_escapes.sx tests/fail/bad_eval.sx tests/fail/bad_external_local_member_func.sx tests/fail/bad_foreach.sx tests/fail/bad_generics.sx tests/fail/bad_imports.sx tests/fail/bad_loops.sx tests/fail/bad_nested_funcs.sx tests/fail/bad_new_delete.sx tests/fail/bad_opt_access.sx tests/fail/bad_opt_lbl.sx tests/fail/bad_overloads.sx tests/fail/bad_pre_una.sx tests/fail/bad_prot_ident.sx tests/fail/bad_range_exp_uses.sx tests/fail/bad_sar.sar tests/fail/bad_selective_import.sar tests/fail/bad_sizeof.sx tests/fail/bad_slices.sx tests/fail/bad_string_switches.sx tests/fail/bad_super_this.sx tests/fail/bad_switches.sx tests/fail/bad_tuples.sx tests/fail/bad_type_expr.sx tests/fail/bad_unittest_decls.sx tests/fail/bad_virt_over.sx tests/fail/bidi1.sx tests/fail/call_exp.sx tests/fail/check_versions_id.sx tests/fail/circular_import_crash.sar tests/fail/circular_inheritance.sx tests/fail/class_decls.sx tests/fail/cover_corner_cases.sx tests/fail/deprecated.sx tests/fail/deprecation_error.sx tests/fail/echo.sx tests/fail/enums.sx tests/fail/escape_return.sx tests/fail/expressions.sx tests/fail/expressions2.sx tests/fail/expressions3.sx tests/fail/expressions4.sx tests/fail/expressions_no_rtl.sx tests/fail/fix_access_in_static.sx tests/fail/fix_over_item_prot.sar tests/fail/fix_selective_import_hide.sar tests/fail/hijack_import.sar tests/fail/illegal_prot_scope.sx tests/fail/import_prot.sar tests/fail/import_scope.sar tests/fail/importer.sx tests/fail/incomplete_qual.sar tests/fail/issue200.sx tests/fail/issue203.sx tests/fail/issue243.sx tests/fail/issue249.sx tests/fail/issue259.sx tests/fail/issue260.sar tests/fail/issue261.sar tests/fail/issue299.sx tests/fail/issue475.sar tests/fail/issue506.sx tests/fail/issue512.sar tests/fail/lbl_nofunc.sx tests/fail/literal_conv.sx tests/fail/local_import_scope.sar tests/fail/local_type_visibility.sx tests/fail/lookup_in_alias.sar tests/fail/member_not_visible.sx tests/fail/missing_returns.sx tests/fail/nested_import.sx tests/fail/nested_import/nested.sx tests/fail/no_deref_func_ptr.sx tests/fail/no_repeat_last.sx tests/fail/noreturn.sx tests/fail/not_reachable.sx tests/fail/param_shadowing.sar tests/fail/protected_member.sar tests/fail/same_param_name.sx tests/fail/same_scope_different_kinds.sx tests/fail/self_import.sx tests/fail/self_import_hint.sar tests/fail/shadow_local_scope.sx tests/fail/static_asserts.sx tests/fail/struct_decls.sx tests/fail/symbolizerb_refact_crash.sx tests/fail/type_in_ident_chain.sx tests/fail/type_size_overflow.sx tests/fail/unit_name_typemod.sx tests/fail/unqual_user.sx tests/fail/var_decls.sx tests/fail/with_expression_not_visible.sx tests/frontend.yml tests/test.d version.txt <<<<<< network # path=library/rtl.gcov -: 0:Source:/builds/styx-lang/styx/library/rtl.sx -: 1:unit rtl; -: 2: -: 3:@foreign function printf(s8* fmt; ...): s32; -: 4:@foreign function free(u8* ptr); -: 5:@foreign function malloc(const usize sz): u8*; -: 6:@foreign function realloc(const u8* ptr; const usize sz): u8*; -: 7:@foreign function memmove(const u8* p1; const u8* p2; const usize sz): u8*; -: 8: -: 9://///////////////////////////// LANGUAGE + RTL VERSIONS //////////////////////// -: 10: -: 11:enum vMajor = 0; -: 12:enum vMinor = 10; -: 13:enum vPatch = 4; -: 14:enum vDevel : bool = true; -: 15: -: 16://///////////////////////// Object - DynCasts - Object Cmp ///////////////////// -: 17: -: 18:/* Common ancestor of all `class` declarations */ -: 19:class Object -: 20:{ -: 21: /* Called for `a == b` and if both operands have non-null and different addresses */ -: 22: @virtual @operator(a==b) function isEqual(Object* other): bool -: 23: { 19258: 24: return false; -: 25: } -: 26:} -: 27: -: 28:/* Called before `a == b` and if both operands are class instances.*/ -: 29:@inline function __sx_obj_equal(const Object* o1; const Object* o2): bool -: 30:{ 118152: 31: const u8* p1 = o1:u8*; 118152: 32: const u8* p2 = o2:u8*; 118152: 33: if p1 == p2 do 71463: 34: return true; 46689: 35: if !p1 || !p2 do 185: 36: return false; 46504: 37: return o1.isEqual(o2); -: 38:} -: 39: -: 40:/* -: 41:struct ClassLayout -: 42:{ -: 43: // actual type is `u8*[N]*` -: 44: // with N = 1 + count of virt funcs -: 45: // and `(*vtbl)[0]` : address of inherited vtbl, used to dyncase -: 46: // `(*vtbl)[1]` : static address of first virt func -: 47: // `(*vtbl)[N]` : static address of last virt func -: 48: var u8* vtbl; -: 49: // super fields ... -: 50: // this fields ... -: 51:} -: 52:*/ -: 53: -: 54:@inline function __sx_obj_dyncast(u8* instance; const u8* targetVtbl): u8* -: 55:{ 99376: 56: var u8* vtbl = *(instance:u8**); 99376: 57: while true do -: 58: { 316510: 59: if vtbl == null do 41328: 60: break instance = null; 275182: 61: if vtbl == targetVtbl do 58048: 62: break; 217134: 63: vtbl = *(vtbl:u8**); -: 64: } 99376: 65: return instance; -: 66:} -: 67: -: 68://///////////////////////// Refcounted Arrays ///////////////////////////////// -: 69: -: 70:/* The part of a ref counted array that resides on the heap */ -: 71:struct RcArray -: 72:{ -: 73: var usize rfc; -: 74: var usize len; -: 75: // followed by the elements ... -: 76:} -: 77: -: 78:function __sx_rc_init(RcArray* array): RcArray* -: 79:{ 544721: 80: if !array do -: 81: { 126221: 82: array = malloc(RcArray.sizeof):RcArray*; -: 83: 127731: 84: if !array do -: 85: assert(0); -: 86: 129996: 87: array.len = 0; 130751: 88: array.rfc = 0; -: 89: } 573061: 90: return array; -: 91:} -: 92: -: 93:function __sx_rc_inc(const RcArray* array) -: 94:{ 2972671: 95: if array do ++(*array).rfc; 1655992: 96:} -: 97: -: 98:function __sx_rc_dec(RcArray* array; const u8* dtor; const u32 elemBitSize): RcArray* -: 99:{ 8655271:100: if array && --(*array).rfc == usize.max do -:101: { 608516:102: if dtor do 2:103: __sx_rc_elemdtor(array, 0, (*array).len, elemBitSize, dtor); 612690:104: free(array:u8*); -:105: //printf("free by refcount\n"); 616468:106: array = null; -:107: } 8690435:108: return array; -:109:} -:110: -:111:function __sx_rc_dec_nest(RcArray* array; const u8 dims): RcArray* -:112:{ 1176:113: if array do -:114: { 69:115: if dims != 0 && (*array).len != 0 do -:116: { 26:117: var RcArray** n = __sx_rc_get_ptr(array):RcArray**; 26:118: foreach const usize i in 0 .. (*array).len do -:119: { 38:120: *n = __sx_rc_dec_nest(*n, dims - 1); 38:121: ++n; -:122: } -:123: } 69:124: if --(*array).rfc == usize.max do -:125: { 67:126: free(array:u8*); -:127: //printf("free by refcount\n"); 67:128: array = null; -:129: } -:130: } 1176:131: return array; -:132:} -:133: -:134:function __sx_rc_before_ret(const RcArray* array) -:135:{ 934100:136: if array do array.rfc -= 1; 482757:137:} -:138: 12245203:139:function __sx_rc_get_length(const RcArray* array): usize { return array ? array.len else 0; } -:140: 0:141:function __sx_rc_get_ref(const RcArray* array): usize { return array ? array.rfc else 0; } -:142: 10761383:143:function __sx_rc_get_ptr(const RcArray* array): u8* { return array && array.len ? array:u8* + RcArray.sizeof else null; } -:144: -:145:function __sx_rc_cpy(RcArray* array; const u32 elemBitSize): RcArray* -:146:{ 131192:147: const usize mallocLen = (__sx_rc_get_length(array) * (elemBitSize / 8)) + RcArray.sizeof; 131192:148: var u8* support = malloc(mallocLen); -:149: 131192:150: if !support do -:151: assert(0); -:152: 131192:153: var RcArray* result = memmove(support, array:u8*, mallocLen): RcArray*; 131192:154: result.len = array.len; 131192:155: result.rfc = 0; 131192:156: return result; -:157:} -:158: -:159:function __sx_rc_dup(RcArray* array; const u32 elemBitSize): RcArray* -:160:{ 65030:161: var RcArray* result = array ? __sx_rc_cpy(array, elemBitSize) else null; 65030:162: result = __sx_rc_init(result); -:163: -:164: // assumed to be set to 0 when .dup is used 65030:165: result.rfc = usize.max; -:166: 65030:167: return result; -:168:} -:169: -:170:function __sx_rc_set_length(RcArray* array; const usize newLen; const u32 elemBitSize): RcArray* -:171:{ 974648:172: const usize oldLen = __sx_rc_get_length(array); 978049:173: if oldLen == newLen do 5516:174: return array; -:175: 981980:176: var RcArray* nu = array; 985381:177: if array && array.rfc != 0 do -:178: { 70178:179: nu = __sx_rc_cpy(array, elemBitSize); 70178:180: __sx_rc_dec(array, null, 0); -:181: } -:182: 1003519:183: const usize mallocLen = (newLen * (elemBitSize / 8)) + RcArray.sizeof; 1006920:184: array = realloc(nu:u8*, mallocLen): RcArray*; -:185: 1012966:186: if !array do -:187: assert(0); -:188: 1021657:189: array.rfc = 0; 1025058:190: array.len = newLen; -:191: 1031104:192: return array; -:193:} -:194: -:195:function __sx_rc_from_slice(RcArray* array; const u8* src; const usize length; const u32 elemBitSize): RcArray* -:196:{ 299653:197: __sx_rc_dec(array, null, 0); -:198: 300787:199: const usize cpyLen = length * (elemBitSize / 8); 301543:200: const usize mallocLen = cpyLen + RcArray.sizeof + 1; 302299:201: array = malloc(mallocLen): RcArray*; -:202: 303433:203: if !array do -:204: assert(0); -:205: 304945:206: array.len = length; 305701:207: array.rfc = 0; -:208: 306835:209: if cpyLen do -:210: { 301567:211: var u8* tgt = __sx_rc_get_ptr(array); 302323:212: memmove(tgt, src, cpyLen); 303079:213: tgt[cpyLen] = 0; -:214: } -:215: 310993:216: return array; -:217:} -:218: -:219:function __sx_rc_append(RcArray* array; const u8* src; const usize length; const u32 elemBitSize): RcArray* -:220:{ 831468:221: array = __sx_rc_init(array); -:222: 836380:223: const usize oldLen = __sx_rc_get_length(array); 839025:224: const usize cpyLen = (length * (elemBitSize / 8)); -:225: 843937:226: array = __sx_rc_set_length(array, oldLen + length, elemBitSize); 846582:227: const u8* p = __sx_rc_get_ptr(array) + (oldLen * (elemBitSize / 8)); -:228: 851494:229: switch cpyLen do -:230: { 259944:231: on 1 do *p = *src; 107236:232: on 2 do *(p:u16*) = *(src:u16*); 19810:233: on 4 do *(p:u32*) = *(src:u32*); 142801:234: on 8 do *(p:u64*) = *(src:u64*); 333718:235: else do memmove(p, src, cpyLen); -:236: } 871898:237: return array; -:238:} -:239: -:240:function __sx_rc_elemdtor(RcArray* array; const usize newLen; const usize oldLen; const u32 elemBitSize; u8* dtor) -:241:{ 2131:242: if newLen >= oldLen do return; -:243: 3:244: const s32 sz = elemBitSize / 8; 3:245: var u8* p = __sx_rc_get_ptr(array) + ((oldLen - 1) * sz); 3:246: const auto f = dtor:function(u8* that)*; -:247: 3:248: foreach const usize i in (newLen .. oldLen).reverse do -:249: { 8:250: f(p); 8:251: p -= sz; -:252: } 3:253:} -:254: -:255://///////////////////////// Builtin Covergage ///////////////////////////////// -:256: -:257:@inline(false) function __sx_finalize_cov(s32* arrayPtr; usize arrayLength; s8* sourceName; s8* reportName) -:258:{ -:259: static function readWholeFile(s32 fd; var s8[+] outData; var s8[] outView) -:260: { -:261: @noinit var s8[4096] buffer; 755:262: while true do -:263: { 3774:264: const auto n = read(fd, buffer.ptr, 4096); 7548:265: if n > 0 do outData ~= buffer.ptr[0 .. n]; 3774:266: if n != 4096 do 755:267: break; -:268: } 755:269: outView = outData[]; 755:270: } -:271: -:272: static function readLine(var s8[] view; s8[+]* outLine) -:273: { -:274: var usize i; 207624:275: while true do -:276: { 7097931:277: if i >= view.length do 0:278: break; 7154162:279: if view.ptr[i] == "\n" do 211399:280: break i++; 6994476:281: i++; -:282: } 213664:283: if outLine do 214042:284: *outLine ~= view.ptr[0 .. i]; 215174:285: view = view[i .. $]; 215929:286: } -:287: -:288: // load source -:289: var s8[+] source; -:290: var s8[] sourceView; 378:291: var s32 sourceFd = open(sourceName, O_RDWR, 0x1B6); 168:292: assert(sourceFd != -1); 378:293: readWholeFile(sourceFd, source, sourceView); 378:294: close(sourceFd); -:295: -:296: // load previous report -:297: var s8[+] report; -:298: var s8[] reportView; -:299: var bool hasPreviousReport; 378:300: var s32 reportFd = open(reportName, O_RDWR, 0x1B6); 378:301: if reportFd > -1 do -:302: { 377:303: readWholeFile(reportFd, report, reportView); 377:304: lseek(reportFd,0,0); 377:305: truncate(reportFd, 0); 377:306: hasPreviousReport = true; -:307: } -:308: else do -:309: { 1:310: reportFd = open(reportName, O_RDWR | O_CREAT, 0x1B6); -:311: } 168:312: assert(reportFd > -1); -:313: 378:314: const s8* digitPad = " "; 378:315: const u8 numDigitsForLine = __numDigits(arrayLength); 378:316: const u8 numDigitsForCount = 10; -:317: -:318: // skip existing tags 378:319: if hasPreviousReport do 377:320: readLine(reportView, null); -:321: -:322: // add tags -:323: var s8[+] tagLine; 378:324: tagLine ~= " -:"; 378:325: tagLine ~= digitPad[0 .. numDigitsForLine - 1]; 378:326: tagLine ~= "0:Source:"; 378:327: tagLine ~= sourceName[0 .. sourceName.strLen()]; 378:328: tagLine ~= "\n"; 378:329: write(reportFd, tagLine.ptr, tagLine.length); -:330: -:331: // foreach line 1 .. $ 378:332: var u32 lineNum = 1; 378:333: while true do -:334: { -:335: var s8[+] sourceLine; -:336: var s8[+] reportLine; -:337: var u32 previousCount; -:338: 128142:339: if lineNum == arrayLength do 0:340: break; 128898:341: if sourceView.length == 0 do 0:342: break; 129654:343: if hasPreviousReport && reportView.length == 0 do 0:344: break; -:345: 130788:346: if hasPreviousReport do -:347: { 131196:348: readLine(reportView, &reportLine); -:349: var usize digitBeg; -:350: var usize digitEnd; 132327:351: while true do -:352: { 1147085:353: if digitBeg == reportLine.length do 0:354: break; 1152728:355: switch reportLine[digitBeg] do -:356: { 1023827:357: on " ", "\t" do continue digitBeg++; 134966:358: else do break; -:359: } -:360: } 136097:361: digitEnd = digitBeg; 136474:362: while true do -:363: { 391504:364: if digitEnd == reportLine.length do 0:365: break; 394775:366: switch reportLine[digitEnd] do -:367: { 258867:368: on "0" .. "9" do continue digitEnd++; 139113:369: else do break; -:370: } -:371: } 140244:372: static const u32[10] decRanks = [1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000]; 140621:373: foreach const auto digitPos in digitBeg .. digitEnd do -:374: { 266826:375: const auto val = reportLine.ptr[digitPos] - "0"; 268907:376: previousCount += decRanks[digitEnd - digitPos + 1] * val ; -:377: } -:378: } -:379: -:380: // count 144018:381: const s32 c = arrayPtr[lineNum]; 144018:382: if c == -1 do -:383: { 80516:384: if 1 < numDigitsForCount do 80516:385: sourceLine ~= digitPad[0 .. numDigitsForCount - 1]; 80516:386: sourceLine ~= "-:"; -:387: } -:388: else do -:389: { 65392:390: var auto s = c:u64 + previousCount:u64; 65770:391: if s > u32.max:u64 do 0:392: s = u32.max; 66526:393: const auto countStr = (s:u32).__u32ToString(); 66904:394: if countStr.length < numDigitsForCount do 67282:395: sourceLine ~= digitPad[0 .. numDigitsForCount - countStr.length]; 67660:396: sourceLine ~= countStr; 68038:397: sourceLine ~= ":"; -:398: } -:399: -:400: // line number 151200:401: var auto lineNumStr = lineNum.__u32ToString(); 151578:402: if lineNumStr.length < numDigitsForLine do 37422:403: sourceLine ~= digitPad[0 .. numDigitsForLine - lineNumStr.length]; 152334:404: sourceLine ~= lineNumStr; 152712:405: sourceLine ~= ":"; -:406: -:407: // line of code 153846:408: readLine(sourceView, &sourceLine); -:409: 154602:410: write(reportFd, sourceLine.ptr, sourceLine.length); 154980:411: lineNum++; -:412: } -:413: 0:414: close(reportFd); 0:415:} -:416: -:417:///////////////////////////// String Switch /////////////////////////////////// -:418: -:419:@public function __sx_ss_lut[u8 minChar, u8 maxChar, u16 numCols, u16 minLen, u16 maxLen](const s8[][] words; s8[] word; const u8* table): u8 -:420:{ -:421: var s32 nextPos; 8369:422: const auto wlen = word.length; 8369:423: if wlen < minLen || wlen > maxLen do 1240:424: return 0; 7129:425: foreach (const auto ci; var auto c) in word do -:426: { 20654:427: if c:u8 < minChar || c:u8 > maxChar do 54:428: return 0; 20600:429: nextPos = table[((1 + c:u8 - minChar) * numCols) + nextPos]; 20600:430: if !nextPos do 3694:431: return 0; 16906:432: const auto nextv = table[nextPos]; 16906:433: if ci + 1 == wlen && nextv && words[nextv - 1] == word do 3275:434: return nextv; -:435: } 106:436: return 0; -:437:} -:438: -:439:protection(private) -:440: -:441:version posix do -:442:{ -:443: enum O_RDWR : s32 = 2; -:444: enum O_CREAT: s32 = 0x40; -:445: -:446: @foreign function read(s32 fd; s8* str; ssize len): ssize; -:447: @foreign function write(s32 fd; s8* str; ssize len): ssize; -:448: @foreign function open(s8* fname; s32 flags; u32 mode): s32; -:449: @foreign function close(s32 fd): s32; -:450: @foreign function lseek(s32 fd; usize offset; s32 whence): s32; -:451: @foreign function truncate(s32 fd; u32 len): s32; -:452:} -:453:else do static assert(0); -:454: -:455:function __u32ToString(u32 value): s8[+] -:456:{ 249426:457: if !value do 6681:458: return "0"; 244257:459: var usize len = 9; -:460: var s8[+] result; 245391:461: result.length = 10; 246147:462: while value do -:463: { 817970:464: result[len--] = (value % 10 + "0"): s8; 821318:465: value /= 10; -:466: } 249171:467: return result[len + 1:usize .. 10:usize]; -:468:} -:469: -:470:function __numDigits(u64 max): u8 -:471:{ 378:472: var u8 result = 6; 378:473: if max < 10 do 0:474: result = 1; 378:475: else do if max < 100 do 0:476: result = 2; 378:477: else do if max < 1000 do 378:478: result = 3; 0:479: else do if max < 10000 do 0:480: result = 4; 0:481: else do if max < 100000 do 0:482: result = 5; 378:483: return result; -:484:} -:485: -:486:function strLen(s8* str): usize -:487:{ -:488: var usize result; 378:489: while true do -:490: { 14400:491: if !str || *str == "\0" do 378:492: break; 14022:493: str++; 14022:494: result++; -:495: } 378:496: return result; -:497:} -:497:} <<<<<< EOF # path=src/algorithms.gcov -: 0:Source:/builds/styx-lang/styx/src/algorithms.sx -: 1:unit algorithms; -: 2: -: 3:function each[Fun, T](T t) -: 4:{ 91468: 5: foreach var auto e in t do 122731: 6: Fun(e); 37092: 7:} -: 8: -: 9:function eachCounted[Fun, T](T t) -:10:{ 856:11: foreach (const auto i; var auto e) in t do 7818:12: Fun(i, e); 856:13:} -:14: -:15:function map[Fun, T](T t): auto -:16:{ 24400:17: const auto len = t.length; 24400:18: @return var auto result = (new echo(type, Fun(t[0]))[+])(len); 24400:19: foreach (const auto i; var auto e) in t.ptr[0 .. len] do 38813:20: result.ptr[i] = Fun(e); 24400:21: return result; -:22:} <<<<<< EOF # path=src/driver.gcov -: 0:Source:/builds/styx-lang/styx/src/driver.sx -: 1:unit driver; -: 2: -: 3:@private import -: 4: system, -: 5: styx.sar, -: 6: styx.session, -: 7: styx.token, -: 8: styx.parser, -: 9: styx.semantic, -: 10: styx.lint, -: 11: ; -: 12: -: 13:function showHelp() -: 14:{ 1: 15: printf("%s\n", -: 16:` -: 17:========================================================================== -: 18: ███████╗████████╗██╗ ██╗██╗ ██╗ -: 19: ██╔════╝╚══██╔══╝╚██╗ ██╔╝╚██╗██╔╝ -: 20: ███████╗ ██║ ╚████╔╝ ╚███╔╝ -: 21: ╚════██║ ██║ ╚██╔╝ ██╔██╗ -: 22: ███████║ ██║ ██║ ██╔╝ ██╗ -: 23: ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ -: 24:========================================================================== -: 25:Command line syntax: -: 26: styx [files] [options] [--] -: 27:files: -: 28: space-separated list of styx source files, styx archives, objects -: 29:stdin: -: 30: after two trailing dashes the compiler takes stdin as source code -: 31:options: -: 32: --be= : define the backend production type, among -: 33: "asm" to produce asm source files (.s) -: 34: "ar" to produce an archive of object (.a) -: 35: "bc" to produce LLVM bitcode files (.bc) -: 36: "exe" to produce a program (the default) -: 37: "ir" to produce LLVM textual representations (.ll) -: 38: "obj" to produce object files (.o) -: 39: --bed= : the directory where the backend writes its production -: 40: --check= : activate additional compiler and runtime checks, among -: 41: "asserts" to generate runtime assertions (the default) -: 42: "bounds" to generate runtime checks on array bounds (the default) -: 43: "dotvars" to generate runtime checks on member read with null this -: 44: "ir" to check the IR before producing object files -: 45: "switches" to generate runtime checks on uncovered switch matches -: 46: "thiscalls" to generate runtime checks on calls with null this -: 47: "all" to enable all optional checks -: 48: "none" to deactivate all checks -: 49: "-" to deactivate the check -: 50: "+" as an alternative to --check= -: 51: --cov : generate coverage information in the gcov textual format -: 52: -d : define the deprecations mode, either -: 53: "disabled" to ignore deprecation messages -: 54: "enabled" to enable them (the default) -: 55: "error" to threat them as errors -: 56: --fforeach-bce : bounds check elimination in foreach bodies, also set starting from -O1 -: 57: --fescape-used : eliminate escapes that are only used to access static members, also set starting from -O1 -: 58: --fno-tls-escapes : if no threads are used then makes local escape faster -: 59: -g : generate debug information -: 60: --gcov : generate debug information, tuned for coverage -: 61: -h | --help : print this message -: 62: -I : add a source or a folder of, parsed in "header" mode -: 63: --lint= : lint the compilation unit(s) with module , either -: 64: "all" to activate all the linter modules -: 65: "suggestOptAssign" to suggest "if statement" to "OptAssignExp" rewrites -: 66: "suggestCondExp" to suggest rewrites to shorter conditional expressions -: 67: "suggestCondToLogical" to suggest rewrite of conditional to logical expressions -: 68: "suggestBreakExp" to suggest using the "break" and "continue" trailing expression -: 69: "unusedLocals" to warn on unused local variables -: 70: "unusedImports" to warn on unused imports -: 71: "assignInAssert" to warn on assignment in assertions -: 72: "reslice" to warn on full reslicing of a slice -: 73: "loopInvariant" to warn when a loop variable could be "const" -: 74: "-" to deactivate the module -: 75: "+" as an alternative to --lint= -: 76: --libc= : set the path to the binaries of the libc to link -: 77: --libc32=: ditto, but prefered with -m32 -: 78: --libc64=: ditto, but prefered with -m64 -: 79: -m : set the target memory model to , either 32 or 64 -: 80: --m= : define the target triplet and specific CPU features -: 81: "--mcpu=" set the CPU model or family, e.g "--mcpu=i386" -: 82: "--mvendor=" set the vendor, e.g "unknown" -: 83: "--mos=" set the OS, e.g "--mos=linux-gnu" -: 84: "--mattr=+" allow emiting specific instructions, e.g "--mattr=+sse2" -: 85: "--mattr=-" forbid emiting specific instructions, e.g "--mattr=-sse4.1" -: 86: -L : add an additional linker argument -: 87: -O : set the backend optimization level to , either 0,1,2 or 3 -: 88: -o : set the output filename -: 89: --rtl= : set the runtime library source file (rtl.sx) -: 90: --run : execute the program, remaining args are used for its args -: 91: -t | --time : measure the time spent to compile -: 92: --until= : stop after phase , either -: 93: "lexical" to stop after the AST construction -: 94: "semantic" to stop after analysis of the program meaning -: 95: --unittest : compile the @unittest functions -: 96: --vid= : add a version identifier -: 97: -v | --verbose : verbose output -: 98: --vforeach-bce : verbose foreach bound checking elimination -: 99: --vescape-used : verbose escapes elimination -:100: --version : print styx version -:101: -w : define the warnings mode, either -:102: "disabled" to deactivate the warnings -:103: "enabled" to enable them (the default) -:104: "error" to threat warnings as errors -:105:` -:106: ); 1:107:} -:108: -:109:function showVersion() -:110:{ 1:111: printf("%s\n", versionToken().text().ptr); 1:112:} -:113: -:114:enum Until -:115:{ -:116: no, -:117: lexical, -:118: semantic, -:119:} -:120: -:121:function main(s32 argc; s8** argv): s32 -:122:{ -:123: version unittest do runTests(); -:124: 374:125: argc--; 374:126: argv++; -:127: var bool wantHelp; -:128: var bool wantVersion; -:129: var bool wantTime; -:130: static var bool wantRun; -:131: static var bool hasSar; -:132: static var bool wantInput; -:133: static var s8[][+] runArgs; -:134: static var Until until; -:135: var s8[+] rtlFileName; -:136: alias lexerParserPairs = session.lexerParserPairs; -:137: -:138: static function onArgument(s8[] arg; s32 index; var bool isHandled): bool -:139: { 919:140: if arg == "--run" do -:141: { 164:142: wantRun = true; 164:143: isHandled = true; 164:144: return 0; -:145: } 755:146: if wantRun do -:147: { 1:148: runArgs ~= arg; 1:149: isHandled = true; 1:150: return 0; -:151: } 754:152: if arg == "--" do -:153: { 2:154: wantInput = true; 2:155: isHandled = true; 2:156: return 0; -:157: } 752:158: if arg.length && arg[0] != "-" do -:159: { 401:160: isHandled = true; 401:161: if !exists(arg) do 3:162: return printMessageAndReturnTrue((`error, the file "` ~ arg ~ "\" does not appear to exist\0").ptr); 398:163: var s8[+] e = fileExt(arg); 398:164: if e == ".a" || e == ".o" do 5:165: session.objects ~= arg; 393:166: else do if e == ".sx" do 339:167: lexerParserPairs ~= (new LexerParserPair).createForFile(arg, false); 54:168: else do if e == ".sar" do -:169: { -:170: var SarItem[+] sis; 53:171: var s8[+] sarContent = fileRead(arg); 53:172: if sarContent.parseSar(sis) do -:173: { 52:174: hasSar = true; 52:175: foreach const auto si in sis do 127:176: lexerParserPairs ~= (new LexerParserPair).createForText(si.fname, si.code, si.line, 0); -:177: } 1:178: else do return printMessageAndReturnTrue((`error, the sar archive "` ~ arg ~ "\" is not properly formatted\0").ptr); -:179: } 1:180: else do return printMessageAndReturnTrue((`error, unrecognized file extension for "` ~ arg ~ "\"\0").ptr); -:181: } 747:182: return 0; -:183: } -:184: -:185: static function onImport(s8[] value): bool -:186: { 6:187: if isDirectory(value) do 4:188: session.imports ~= value; 2:189: else do if isFile(value) && fileExt(value) == ".sx" do 1:190: lexerParserPairs ~= (new LexerParserPair).createForFile(value, true); 6:191: return false; -:192: } -:193: -:194: static function onUntil(s8[] value): bool -:195: { 6:196: if value == "lexical" do until = Until.lexical; 7:197: else do if value == "semantic" do until = Until.semantic; 1:198: else do return printMessageAndReturnTrue("invalid `--until` argument, expected `lexical` or `semantic`"); 4:199: return false; -:200: } -:201: 374:202: with OptionHandler do -:203: { 374:204: add(0, "be", &session.setBeKind); 374:205: add(0, "bed", &session.beDir); 374:206: add(0, "check", &session.addAdditionalCheck); 374:207: add(0, "cov", &session.setCov); 374:208: add("d", "", &session.setDeprecationType); 374:209: add(0, "fescape-used", &session.escapeUsed); 374:210: add(0, "fforeach-bce", &session.foreachBCE); 374:211: add("g", "", &session.generateDebugInfo); 374:212: add(0, "gcov", &session.setGcov); 374:213: add("h", "help", &wantHelp); 374:214: add("I", "", &onImport); 374:215: add("L", "", &session.addLinkerArg); 374:216: add(0, "lint", &session.addLinterModule); 374:217: add("m", "", &session.setRegSize); 374:218: add(0, "mcpu", &MachineTarget.setCpu); 374:219: add(0, "mvendor", &MachineTarget.setVendor); 374:220: add(0, "mos", &MachineTarget.setOs); 374:221: add(0, "mattr", &MachineTarget.addFeature); 374:222: add("O", "", &session.setOptLevel); 374:223: add("o", "of", &session.outputFilename); 374:224: add(0, "rtl", &rtlFileName); 374:225: add(0, "unittest", &session.setCompileUnittest); 374:226: add(0, "until", &onUntil); 374:227: add("t", "time", &wantTime); 374:228: add(0, "version", &wantVersion); 374:229: add("v", "verbose", &session.verbose); 374:230: add(0, "vescape-used", &session.vescapeUsed); 374:231: add(0, "vforeach-bce", &session.vforeachBCE); 374:232: add(0, "vid", &session.addVersion); 374:233: add("w", "", &session.setWarningType); 374:234: add(0, "fno-tls-escapes", &session.noTlsEscapes); 373:235: processArguments(argc, argv, &onArgument); 373:236: if hasErrors do 15:237: return 1; -:238: } -:239: 358:240: if wantHelp do -:241: { 1:242: showHelp(); 1:243: return 0; -:244: } 357:245: if wantVersion do -:246: { 1:247: showVersion(); 1:248: return 0; -:249: } 356:250: if wantInput do -:251: { -:252: // note : readInput() does not work if system.Process @unittest functions are executed 2:253: var s8[+] input = readInput(); -:254: var SarItem[+] sis; 2:255: if input.parseSar(sis) do -:256: { 1:257: hasSar = true; 1:258: foreach const auto si in sis do 2:259: lexerParserPairs ~= (new LexerParserPair).createForText(si.fname, si.code, si.line, 0); -:260: } 1:261: else do lexerParserPairs ~= (new LexerParserPair).createForText("stdin", input, 0, 0); -:262: } 356:263: if !lexerParserPairs.length && !wantInput do -:264: { 3:265: printf("nothing to compile !\n"); 3:266: return 0; -:267: } 353:268: if rtlFileName.length do -:269: { 46:270: session.hasRtl = true; 46:271: lexerParserPairs ~= (new LexerParserPair).createForFile(rtlFileName, false); -:272: } 353:273: if hasSar && session.cover do 1:274: return printMessageAndReturnTrue("error, `--cov` cannot be used with .sar files"); -:275: 357:276: if wantTime do Timer.start(); -:277: -:278: // lexical passes 352:279: foreach const LexerParserPair* p in lexerParserPairs do -:280: { 519:281: if session.verbose do printf("parsing %s...\n", p.filename.ptr); 1018:282: if var auto u = p.parser.parseUnitDeclaration() do -:283: { 1014:284: if var auto lm = session.linterModules do 12:285: postLexicalPassLint(u, lm); -:286: } 2:287: else do return 1; -:288: } 355:289: if wantTime do printf("lexical passes duration: %s\n", Timer.peekString().ptr); 351:290: if until == Until.lexical do return 0; -:291: -:292: // semantic passes 349:293: foreach const LexerParserPair* p in lexerParserPairs do -:294: { 511:295: if session.verbose do printf("pre-semantic for %s...\n", p.filename.ptr); 501:296: if !preSemantic(p.parser.getUnit()) do 14:297: return 1; -:298: } -:299: // foreach over range : linkImports may append to (i.e reallocate) lexerParserPairs 335:300: const usize knowCount = lexerParserPairs.length; 335:301: foreach const auto i in 0 .. knowCount do -:302: { 484:303: const auto p = lexerParserPairs.ptr[i]; 494:304: if session.verbose do printf("attaching imports for %s...\n", p.filename.ptr); 484:305: if !linkImports(p.parser.getUnit()) do 6:306: return 1; -:307: } 329:308: foreach const LexerParserPair* p in lexerParserPairs do -:309: { 482:310: if session.verbose do printf("semantic for %s...\n", p.filename.ptr); 472:311: if !semantic(p.parser.getUnit()) do 83:312: return 1; 778:313: if var auto lm = session.linterModules do 12:314: postSemanticPassLint(p.parser.getUnit(), lm); -:315: } 250:316: if wantTime do printf("semantic passes duration: %s\n", Timer.peekString().ptr); 248:317: if until == Until.semantic do return 0; -:318: -:319: // backend pass -:320: version llvm do -:321: { -:322: import styx.backend; -:323: 189:324: foreach const LexerParserPair* p in lexerParserPairs do -:325: { 293:326: if session.verbose do printf("IR generation for %s...\n", p.filename.ptr); 288:327: if !p.isImport && !produceIR(p.parser.getUnit()) do 1:328: return 1; -:329: } 190:330: if wantTime do printf("irgen pass duration: %s\n", Timer.peekString().ptr); 187:331: if session.beKind == BackendOutputKind.exe do -:332: { 172:333: if session.verbose do printf("linking the application...\n"); 171:334: if !linkExecutable() do 1:335: return 1; 171:336: if wantTime do printf("linking duration: %s\n", Timer.peekString().ptr); 170:337: if wantRun do -:338: { -:339: var Process p; 164:340: p.executable = (absolutePath(session.outputFilename) ~ "\0").ptr; 164:341: p.redirects = [err, out]; 164:342: foreach var auto a in runArgs do 1:343: p.arguments ~= (a ~ "\0").ptr; -:344: var s8[+] stdOut; -:345: var s8[+] stdErr; 164:346: p.execute(); 164:347: var s32 r = p.waitAndRead(&stdOut, &stdErr); 164:348: if stdOut.length do -:349: { 54:350: stdOut ~= "\0"; 54:351: puts(stdOut.ptr); -:352: } 164:353: if stdErr.length do -:354: { 1:355: stdErr ~= "\0"; 1:356: puts(stdErr.ptr); -:357: } -:358: 164:359: printf("inferior exit status: %s\n", prettyExitStatus(r).ptr); 164:360: return r < 0 ? -r else r; -:361: } -:362: } 16:363: else do if session.beKind == BackendOutputKind.ar do -:364: { 4:365: if session.verbose do printf("archiving the objects...\n"); 2:366: if !linkArchive() do 0:367: return 1; 4:368: if wantTime do printf("linking duration: %s\n", Timer.peekString().ptr); -:369: } -:370: } -:371: 77:372: return 0; -:373:} -:374: -:375: -:376:version unittest do function runTests() -:377:{ -:378: printf("running `system` tests...\n"); -:379: import system; -:380: foreach const auto t in echo(getUnittests, system) do t(); -:381: printf("running `styx.sar` tests...\n"); -:382: import styx.sar; -:383: foreach const auto t in echo(getUnittests, styx.sar) do t(); -:384: printf("running `styx.position` tests...\n"); -:385: import styx.position; -:386: foreach const auto t in echo(getUnittests, styx.position) do t(); -:387: printf("running `styx.token` tests...\n"); -:388: import styx.token; -:389: foreach const auto t in echo(getUnittests, styx.token) do t(); -:390: printf("running `styx.lexer` tests...\n"); -:391: import styx.lexer; -:392: foreach const auto t in echo(getUnittests, styx.lexer) do t(); -:393: printf("running `styx.ast.types` tests...\n"); -:394: import styx.ast.types; -:395: foreach const auto t in echo(getUnittests, styx.ast.types) do t(); -:396: printf("running `styx.parser` tests...\n"); -:397: import styx.parser; -:398: foreach const auto t in echo(getUnittests, styx.parser) do t(); -:399: printf("running `styx.ast.formatter` tests...\n"); -:400: import styx.ast.formatter; -:401: foreach const auto t in echo(getUnittests, styx.ast.formatter) do t(); -:402: printf("running `styx.semantic.smbolize` tests...\n"); -:403: import styx.semantic.symbolize; -:404: foreach const auto t in echo(getUnittests, styx.semantic.symbolize) do t(); -:405:} <<<<<< EOF # path=src/system.gcov -: 0:Source:/builds/styx-lang/styx/src/system.sx -: 1:unit system; -: 2: -: 3:version posix && X86_64 do {} -: 4:else do static assert(0, "unsupported platform"); -: 5: -: 6:struct va_list -: 7:{ -: 8: var u32 offset_regs = 6 * 8; -: 9: var u32 offset_fpregs = 6 * 8 + 8 * 16; -: 10: var u8* stack_args; -: 11: var u8* reg_args; -: 12:} -: 13: -: 14:@LLVM function va_start(u8* va); -: 15:@LLVM function va_copy(u8* src; u8* dest); -: 16:@LLVM function va_end(u8* va); -: 17: -: 18:@LLVM("uadd.with.overflow.i64") function uadd64(u64 a; u64 b): (u64,bool); -: 19:@LLVM("umul.with.overflow.i64") function umul64(u64 a; u64 b): (u64,bool); -: 20: -: 21:@foreign function exit(s32 code); -: 22: -: 23:@foreign function puts(s8* text): s32; -: 24:@foreign function vprintf(s8* specifier; va_list* va): s32; -: 25:@foreign function printf(s8* specifier; ...): s32; -: 26:@foreign function snprintf(s8 *str; usize len; s8* specifier; ...): s32; -: 27: -: 28:@foreign function strlen(s8* str): s32; -: 29: -: 30:@foreign function free(u8* otr); -: 31: -: 32:@foreign function getcwd (s8* buffer; usize size): s8*; -: 33: -: 34:@foreign struct File; -: 35: -: 36:@foreign @tls var s32 errno; -: 37: -: 38:enum ERANGE : s32 = 34; -: 39: -: 40:version posix do -: 41:{ -: 42: -: 43:// --- libc --- // -: 44: enum SeekFrom -: 45: { -: 46: start = 0, -: 47: here = 1, -: 48: end = 2, -: 49: } -: 50: -: 51: struct Dirent -: 52: { -: 53: enum Dt : s8 -: 54: { -: 55: DT_UNKNOWN = 0, -: 56: DT_FIFO = 1, -: 57: DT_CHR = 2, -: 58: DT_DIR = 4, -: 59: DT_BLK = 6, -: 60: DT_REG = 8, -: 61: DT_LNK = 10, -: 62: DT_SOCK = 12, -: 63: } -: 64: var u64 d_ino; -: 65: var s64 d_off; -: 66: var u16 d_reclen; -: 67: var Dt d_type; -: 68: var s8[256] d_name; -: 69: 10: 70: function isFile(): bool { return d_type == Dt.DT_REG; } 10: 71: function isDir(): bool { return d_type == Dt.DT_DIR; } 10: 72: function name(): s8[+] { return d_name[0 .. strlen(d_name.ptr)]; } -: 73: } -: 74: -: 75: struct Dir; -: 76: -: 77: @foreign function mkdir (const s8 *filename; s32 mode): s32; -: 78: @foreign function remove(const s8* pathname): s32; -: 79: -: 80: @foreign function opendir(const s8* name): Dir* ; -: 81: @foreign function closedir(Dir* dir); -: 82: @foreign function readdir(Dir* dir): Dirent*; -: 83: @foreign function strtod(const s8* str; s8** tailstr): f64; -: 84: -: 85:// --- unistd --- // -: 86: -: 87: alias Pid = s32; -: 88: -: 89: struct PipeFD -: 90: { -: 91: var s32 readEnd; -: 92: var s32 writeEnd; -: 93: } -: 94: -: 95: struct TimeSpec -: 96: { -: 97: var s64 sec; /* seconds */ -: 98: var s64 nsec; /* nanoseconds */ -: 99: } -: 100: -: 101: enum POLLIN : u16 = 0x001; -: 102: -: 103: struct PollFd -: 104: { -: 105: var s32 fd; /* file descriptor */ -: 106: var u16 events; /* requested events */ -: 107: var u16 revents; /* returned events */ -: 108: -: 109: @constructor function create(s32 fd; u16 events) -: 110: { 5832: 111: this.fd = fd; 5832: 112: this.events = events; 5832: 113: } -: 114: } -: 115: -: 116: enum OpenFlags : s32 -: 117: { -: 118: O_RDONLY = 0x0, -: 119: O_WRONLY = 0x1, -: 120: O_RDWR = 0x2, -: 121: O_CREAT = 0x40, -: 122: O_DIRECT = 0x004000, -: 123: } -: 124: -: 125: @foreign function close(s32 fd): s32; -: 126: @foreign function dup2(s32 oldfd; s32 newFd): s32; -: 127: @foreign function execv(const s8* pathname; const s8** argv): s32; -: 128: @foreign function fflush(usize fd); -: 129: @foreign function fork(): Pid; -: 130: @foreign function nanosleep(TimeSpec* req; TimeSpec* rem = null): s32; -: 131: @foreign function pipe(var PipeFD pf): s32; -: 132: @foreign function poll(PollFd* fds; s32 nfds; s32 timeout): s32; -: 133: @foreign function read(s32 fd; s8* buff; usize count): usize; -: 134: @foreign function waitpid(Pid pid; s32* status; s32 options): Pid; -: 135: @foreign function write(s32 fd; s8* buff; usize count): usize; -: 136: @foreign function open(s8* fname; s32 flags; u32 mode): s32; -: 137: @foreign function lseek(s32 fd; usize offset; s32 whence): s32; -: 138: -: 139: @foreign function clock_gettime(s32 clockid; TimeSpec* tp): s32; -: 140: -: 141: enum STDIN_FILENO : s32 = 0; -: 142: enum STDOUT_FILENO : s32 = 1; -: 143: enum STDERR_FILENO : s32 = 2; -: 144: enum WNOHANG : s32 = 1; -: 145: enum CLOCK_MONOTONIC : s32 = 1; -: 146: -: 147: struct stat_t -: 148: { -: 149: // dont actually bother more with the definition as only -: 150: // `mode_t st_mode` is required by the following utils. -: 151: var u8[512] _; -: 152: -: 153: version X86_64 do -: 154: @inline function getMode(): u32 -: 155: { 11: 156: return *(((this:u8*) + 24): u32*); -: 157: } -: 158: } -: 159: -: 160: @foreign function stat(const s8* pathname; stat_t* statbuf): s32; -: 161:} -: 162: -: 163:// --- wait.h --- // -: 164: -: 165:enum __W_CONTINUED : s32 = 0xFFFF; 339: 166:function __WTERMSIG(s32 status): s32 { return status & 0x7F; } 328: 167:function WEXITSTATUS(s32 status):s32 { return ( status & 0xFF00 ) >> 8; } -: 168://function WIFCONTINUED(s32 status):s32 { return status == __W_CONTINUED; } 339: 169:function WIFEXITED(s32 status): bool { return __WTERMSIG( status ) == 0; } 11: 170:function WIFSIGNALED(s32 status): bool { return ((( status & 0x7F ) + 1):u8 >> 1) > 0;} -: 171: -: 172://function WIFSTOPPED(s32 status): bool { return ( status & 0xFF ) == 0x7F; } -: 173://function WSTOPSIG(s32 status): s32 { return WEXITSTATUS( status ); } 11: 174:function WTERMSIG(s32 status):s32 { return status & 0x7F; } -: 175: -: 176:// like assert(0, message) but does not show file info -: 177:function ErrorAndExit1(s8* message) -: 178:{ 1: 179: printf("%s\n", message); 1: 180: fflush(0); 0: 181: exit(1); 0: 182:} -: 183: -: 184:// like assert(0, message) but does not show file info -: 185:function printMessageAndReturnTrue(s8* message): bool -: 186:{ 16: 187: printf("%s\n", message); 16: 188: fflush(0); 16: 189: return true; -: 190:} -: 191: -: 192:function firstIndexOfChar(s8[] str; s8 value): ssize -: 193:{ 3: 194: foreach (const auto i; const s8 c) in str do 4: 195: if c == value do 1: 196: return i; 2: 197: return -1; -: 198:} -: 199: -: 200:@unittest function test1() -: 201:{ -: 202: assert(firstIndexOfChar("", ".") == -1); -: 203: assert(firstIndexOfChar("aa", ".") == -1); -: 204: assert(firstIndexOfChar("a.a.", ".") == 1); -: 205:} -: 206: -: 207:function lastIndexOfChar(s8[] str; s8 value): ssize -: 208:{ 477: 209: var ssize pos = str.length-1; 477: 210: while pos != -1 do -: 211: { 1869: 212: if str[pos] == value do 463: 213: break; 1406: 214: pos -= 1; -: 215: } 477: 216: return pos; -: 217:} -: 218: -: 219:@unittest function testLastIndexOfChar() -: 220:{ -: 221: assert(lastIndexOfChar("", ".") == -1); -: 222: assert(lastIndexOfChar("aa", ".") == -1); -: 223: assert(lastIndexOfChar("a.a.", ".") == 3); -: 224:} -: 225: -: 226:function startsWith(s8[] str; s8[] subStr): bool -: 227:{ 2683: 228: const usize subLen = subStr.length; 2683: 229: return str.length >= subLen && str[0 .. subLen] == subStr; -: 230:} -: 231: -: 232:@unittest function testStartsWith() -: 233:{ -: 234: assert(startsWith("", "")); -: 235: assert(!startsWith("", "prefix")); -: 236: assert(startsWith("prefix", "prefix")); -: 237: assert(startsWith("prefixOther", "prefix")); -: 238:} -: 239: -: 240:function fileExt(s8[] filename): s8[+] -: 241:{ -: 242: @return var s8[+] result; 419: 243: const ssize p = filename.lastIndexOfChar("."); 419: 244: if p > 0 && p + 1 != filename.length do 416: 245: result = filename[p .. $]; 419: 246: return result; -: 247:} -: 248: -: 249:function baseName(s8[] filename): s8[+] -: 250:{ -: 251: @return var s8[+] result; 55: 252: const usize len = filename.length; 55: 253: const usize r = len && filename[$-1] == "/" ? len - 1 else len; 55: 254: const ssize p = filename[0 .. r].lastIndexOfChar("/"); 55: 255: result = filename[p + 1 .. r]; 55: 256: return result; -: 257:} -: 258: -: 259:@unittest function testBaseName() -: 260:{ -: 261: assert(baseName("a") == "a"); -: 262: assert(baseName("a/") == "a"); -: 263: assert(baseName("a/b") == "b"); -: 264:} -: 265: -: 266:@unittest function testFileExt() -: 267:{ -: 268: assert(fileExt("") == ""); -: 269: assert(fileExt("aa") == ""); -: 270: assert(fileExt("a.a") == ".a"); -: 271:} -: 272: -: 273:function setExtension(s8[] filename; s8[] ext): s8[+] -: 274:{ 14: 275: @return var s8[+] result = filename; 14: 276: var s8[+] e = fileExt(filename); 14: 277: if e != ext do 13: 278: result = result[0 .. $ - e.length] ~ ext; 14: 279: return result; -: 280:} -: 281: -: 282:@unittest function testSetExtension() -: 283:{ -: 284: assert(setExtension("a.a", ".a") == "a.a"); -: 285: assert(setExtension("a", ".a") == "a.a"); -: 286:} -: 287: -: 288:function isAbsolutePath(const s8[] name): bool -: 289:{ 228: 290: return name && name.ptr[0] == "/"; -: 291:} -: 292: -: 293:@unittest function testIsAbsolutePath() -: 294:{ -: 295: assert(!isAbsolutePath("")); -: 296: assert(!isAbsolutePath("a")); -: 297: assert(isAbsolutePath("/usr")); -: 298:} -: 299: -: 300:function currentWorkingDirectory(): s8[+] -: 301:{ -: 302: @return var s8[+] result; 225: 303: var s8* r = getcwd(null, 0); 225: 304: const usize len = strlen(r); 225: 305: result = r[0 .. len]; 225: 306: free(r:u8*); 225: 307: return result; -: 308:} -: 309: -: 310:@unittest function testCurrentWorkingDirectory() -: 311:{ -: 312: assert(isAbsolutePath(currentWorkingDirectory())); -: 313: assert(isDirectory(currentWorkingDirectory())); -: 314:} -: 315: -: 316:function absolutePath(s8[] name): s8[+] -: 317:{ 224: 318: if isAbsolutePath(name) do 1: 319: return name; 223: 320: @return var s8[+] result = currentWorkingDirectory(); 223: 321: const usize cwdLen = result.length; 223: 322: if name.startsWith("./") do -: 323: { 5: 324: result.length += name.length - 1; 5: 325: result[cwdLen .. $] = name[1 .. $]; -: 326: } -: 327: else do -: 328: { 218: 329: result.length += name.length + 1; 218: 330: result[cwdLen] = "/"; 218: 331: result[cwdLen + 1 .. $] = name[]; -: 332: } 223: 333: return result; -: 334:} -: 335: -: 336:@unittest function coverAbsolutePath() -: 337:{ -: 338: const auto a = absolutePath("/usr"); -: 339: const auto b = absolutePath("bin"); -: 340: const auto d = absolutePath("./bin"); -: 341:} -: 342: -: 343:function dirName(s8[] name): s8[+] -: 344:{ -: 345: @return var s8[+] result; 224: 346: var usize i = name.length; 224: 347: const auto ptr = name.ptr; 224: 348: while true do -: 349: { 1758: 350: if i == 0 do 8: 351: break result = "./"; 1750: 352: if ptr[--i] == "/" do 216: 353: break result = ptr[0 .. i]; -: 354: } 224: 355: return result; -: 356:} -: 357: -: 358:@unittest function testDirName() -: 359:{ -: 360: assert(dirName("a") == "./"); -: 361: assert(dirName("/a/b") == "/a"); -: 362:} -: 363: -: 364:function exists(s8[] filename): bool -: 365:{ -: 366: version posix do -: 367: { -: 368: @noinit var stat_t s; 1547: 369: return stat(filename.ptr, &s) == 0; -: 370: } -: 371: else do static assert(0); -: 372:} -: 373: -: 374:@unittest function testExists() -: 375:{ -: 376: assert(exists(echo(filename))); -: 377: assert(!exists("/::x/x::/x/x/:x:/z/z/0/1")); -: 378:} -: 379: -: 380:function isFile(s8[] filename): bool -: 381:{ -: 382: version posix do -: 383: { -: 384: @noinit var stat_t s; 4: 385: if stat(filename.ptr, &s) == 0 do -: 386: { -: 387: enum S_IFREG : u32 = 0x8000; 3: 388: return (s.getMode() & S_IFREG) != 0; -: 389: } 1: 390: else do return false; -: 391: } -: 392: else do static assert(0); -: 393:} -: 394: -: 395:@unittest function testIsFile() -: 396:{ -: 397: assert(isFile(echo(filename))); -: 398: assert(!isFile("/usr/bin")); -: 399:} -: 400: -: 401:function isDirectory(s8[] filename): bool -: 402:{ -: 403: version posix && X86_64 do -: 404: { -: 405: @noinit var stat_t s; 9: 406: if stat(filename.ptr, &s) == 0 do -: 407: { -: 408: enum S_IFDIR : u32 = 0x4000; 8: 409: return (s.getMode() & S_IFDIR) != 0; -: 410: } 1: 411: else do return false; -: 412: } -: 413: else do static assert(0); -: 414:} -: 415: -: 416:@unittest function testIsDirectory() -: 417:{ -: 418: assert(!isDirectory(echo(filename))); -: 419: assert(isDirectory("/usr/bin")); -: 420:} -: 421: -: 422:function createDir(s8[] pathname) -: 423:{ 4: 424: const s8[] left = dirName(pathname); 4: 425: if left.length != pathname.length && !exists(left) do -: 426: { 1: 427: createDir(left); -: 428: } 4: 429: if baseName(pathname).length do -: 430: { 4: 431: mkdir(pathname.ptr, 0x1FF); -: 432: } 4: 433:} -: 434: -: 435:function fileRead(s8[] filename): s8[+] -: 436:{ -: 437: @return var s8[+] result; -: 438: version posix do -: 439: { 892: 440: if var auto f = open(filename.ptr, OpenFlags.O_RDONLY, 0x1B6 | OpenFlags.O_DIRECT) do -: 441: { 446: 442: result.length = lseek(f, 0, SeekFrom.end); 446: 443: lseek(f, 0, SeekFrom.start); 446: 444: read(f, result.ptr, result.length); 446: 445: close(f); -: 446: } -: 447: } -: 448: else do static assert (0); -: 449: 446: 450: return result; -: 451:} -: 452: -: 453:function fileWrite(s8[] filename; s8[] data) -: 454:{ -: 455: version posix do -: 456: { 10: 457: if var auto f = open(filename.ptr, OpenFlags.O_RDWR | OpenFlags.O_CREAT, 0x1B6) do -: 458: { 5: 459: write(f, data.ptr, data.length); 5: 460: close(f); -: 461: } -: 462: } -: 463: else do static assert (0); 5: 464:} -: 465: -: 466:@unittest function testFileWriteRead() -: 467:{ -: 468: const s8[+] text = "file content"; -: 469: const s8[+] fname = "__test_write_read.txt"; -: 470: fileWrite(fname, text); -: 471: var auto r = fileRead(fname); -: 472: assert(r[] == text); -: 473: fname.ptr.remove(); -: 474:} -: 475: -: 476:enum DirEntryKind : u8 -: 477:{ -: 478: directory, -: 479: file, -: 480:} -: 481: -: 482:alias DirEntryAcceptFun = static function(const s8[] name; const DirEntryKind kind): bool; -: 483: -: 484:function dirEntries(const s8[] path; DirEntryAcceptFun* afun = null): s8[+][+] -: 485:{ -: 486: @return var s8[+][+] result; 4: 487: if var Dir* d = opendir(path.ptr) do -: 488: { -: 489: var Dirent* de; 2: 490: while (de = readdir(d)) do -: 491: { 10: 492: var s8[+] ename = de.name(); 10: 493: const bool isFile = de.isFile(); 10: 494: const bool isDir = de.isDir(); 10: 495: if isFile || isDir do -: 496: { 10: 497: if afun do -: 498: { 5: 499: if afun(ename[], isFile ? DirEntryKind.file else DirEntryKind.directory) do 2: 500: result ~= ename; -: 501: } 5: 502: else do result ~= ename; -: 503: } -: 504: } 2: 505: closedir(d); -: 506: } 2: 507: return result; -: 508:} -: 509: -: 510:@unittest function testDirEntries() -: 511:{ -: 512: createDir("testdir/td"); -: 513: fileWrite("testdir/td/a.txt", "text"); -: 514: fileWrite("testdir/td/b.txt", "text"); -: 515: fileWrite("testdir/td/c.md", "markdown"); -: 516: -: 517: var s8[+][+] entries = dirEntries("./testdir/td", function f(const s8[] n; const DirEntryKind k): bool => -: 518: (k == file && fileExt(n) == ".txt") -: 519: ); -: 520: assert(entries.length == 2); -: 521: -: 522: var s8[+][+] entries2 = dirEntries("./testdir/td"); -: 523: assert(entries2.length == 5); // dirs ".", ".." -: 524: -: 525: remove("testdir/td/a.txt"); -: 526: remove("testdir/td/b.txt"); -: 527: remove("testdir/td/c.md"); -: 528: remove("testdir"); -: 529:} -: 530: -: 531:@overload(toString) function u32ToString(u32 value): s8[+] -: 532:{ 19967: 533: if !value do 729: 534: return "0"; 19238: 535: var usize len = 9; 19238: 536: var s8[+] result = (new s8[+])(10); 19238: 537: while value do -: 538: { 52953: 539: result.ptr[len--] = (value % 10 + "0"): s8; 52953: 540: value /= 10; -: 541: } 19238: 542: return result.ptr[len + 1 .. 10]; -: 543:} -: 544: -: 545:@unittest function testU32ToString() -: 546:{ -: 547: assert(u32ToString(0) == "0"); -: 548: assert(u32ToString(1) == "1"); -: 549: assert(u32ToString(11) == "11"); -: 550: assert(u32ToString(u32.max) == (u32.max).stringof); -: 551:} -: 552: -: 553:function strToU64(s8[] str; const u32 base; var u64 result): bool -: 554:{ 9910: 555: result = 0; -: 556: -: 557: var bool of; -: 558: var s8 c; 9910: 559: var auto length = str.length; 9910: 560: var auto ptr = str.ptr; 9910: 561: var auto rank = 1:u64; -: 562: 9910: 563: while length > 0 do -: 564: { 15787: 565: if of do return false; 15787: 566: const auto i = length - 1; -: 567: var u64 v; 15787: 568: switch c = ptr[i] do -: 569: { 42: 570: on "_" do continue length -= 1; 7141: 571: on "0" do v = 0; 3694: 572: on "1" do v = 1; 1160: 573: on "2" do v = 2; 509: 574: on "3" do v = 3; 737: 575: on "4" do v = 4; 292: 576: on "5" do v = 5; 541: 577: on "6" do v = 6; 219: 578: on "7" do v = 7; 714: 579: on "8" do v = 8; 405: 580: on "9" do v = 9; 5: 581: on "A", "a" do v = 10; 142: 582: on "B", "b" do v = 11; 6: 583: on "C", "c" do v = 12; 1: 584: on "D", "d" do v = 13; 8: 585: on "E", "e" do v = 14; 171: 586: on "F", "f" do v = 15; -: 587: else do assert(0); -: 588: } 15745: 589: (v , of) = umul64(v, rank); 15747: 590: if of do return false; 15743: 591: (result, of) = uadd64(result, v); 15743: 592: if of do return false; -: 593: -: 594: // checked on entry, b/c rank might overflow but wont be used 15743: 595: (rank, of) = umul64(rank, base); -: 596: 15743: 597: length -= 1; -: 598: } -: 599: 9908: 600: return true; -: 601:} -: 602: -: 603:@unittest function testStrToU64() -: 604:{ -: 605: var u64 r; -: 606: -: 607: strToU64("0", 10, r); -: 608: assert(r == 0); -: 609: strToU64("9", 10, r); -: 610: assert(r == 9); -: 611: strToU64("100", 10, r); -: 612: assert(r == 100); -: 613: strToU64("100_432", 10, r); -: 614: assert(r == 100432); -: 615: -: 616: strToU64("0", 16, r); -: 617: assert(r == 0); -: 618: strToU64("9", 16, r); -: 619: assert(r == 9); -: 620: strToU64("F", 16, r); -: 621: assert(r == 15); -: 622: strToU64("F_f", 16, r); -: 623: assert(r == 255); -: 624: -: 625: strToU64("11", 2, r); -: 626: assert(r == 3); -: 627: strToU64("110", 2, r); -: 628: assert(r == 6); -: 629: -: 630: assert( !strToU64("99999999999999999999999999", 10, r)); -: 631: assert( strToU64("8_000_000_000", 10, r)); -: 632: assert( strToU64("CBF29CE484222325", 16, r)); -: 633:} -: 634: -: 635:enum ProcessStream : u8 -: 636:{ -: 637: inp, -: 638: out, -: 639: err, -: 640:} -: 641: -: 642:alias ProcessStreams = bool[ProcessStream]; -: 643: -: 644:alias ProcessErrorHandler = static function(Process* p; ProcessError pe)*; -: 645: -: 646:enum ProcessError -: 647:{ -: 648: forkFail, -: 649: pipeInFail, -: 650: pipeOutFail, -: 651: pipeErrFail, -: 652: pollFail, -: 653: execvFail, -: 654: waitFail, -: 655:} -: 656: -: 657:function defaultProcessErrorHandler(Process* p; ProcessError pe) -: 658:{ 0: 659: p.terminated = true; 0: 660: switch pe do -: 661: { 0: 662: on ProcessError.forkFail do ErrorAndExit1("Process error, impossible to fork"); 0: 663: on ProcessError.pipeInFail do ErrorAndExit1("Process error, impossible to create the pipe for stdin"); 0: 664: on ProcessError.pipeOutFail do ErrorAndExit1("Process error, impossible to create the pipe for stdout"); 0: 665: on ProcessError.pipeErrFail do ErrorAndExit1("Process error, impossible to create the pipe for stderr"); 0: 666: on ProcessError.pollFail do ErrorAndExit1("Process error, poll failed"); 0: 667: on ProcessError.execvFail do ErrorAndExit1("Process error, execv failed"); 0: 668: on ProcessError.waitFail do ErrorAndExit1("Process error, waitpid failed"); -: 669: } 0: 670:} -: 671: -: 672:var ProcessErrorHandler onProcessError = &defaultProcessErrorHandler; -: 673: -: 674:struct Process -: 675:{ -: 676: var s8* executable; -: 677: var s8*[+] arguments; -: 678: var ProcessStreams redirects; -: 679: var Pid pid; -: 680: var PipeFD[3] pipes; -: 681: var s32 exitCode; -: 682: var bool terminated; -: 683: -: 684: @destructor function destroy() -: 685: { 340: 686: arguments.decref; 340: 687: } -: 688: -: 689: function cleanup() -: 690: { 340: 691: foreach const auto p in pipes do -: 692: { 1020: 693: close(p.readEnd); 1020: 694: close(p.writeEnd); 1020: 695: p.readEnd = -1; 1020: 696: p.writeEnd = -1; -: 697: } 340: 698: terminated = false; 340: 699: exitCode = 0; 340: 700: } -: 701: -: 702: function closeStream(ProcessStream ps) -: 703: { 1: 704: switch ps do -: 705: { 1: 706: on inp do if ps in redirects do 1: 707: close(pipes[ps].writeEnd); 0: 708: on out, err do if ps in redirects do 0: 709: close(pipes[ps].readEnd); -: 710: } 1: 711: } -: 712: -: 713: function writeStreamBuffer(ProcessStream ps; s8[] buffer) -: 714: { 1: 715: if ps in redirects do 1: 716: write(pipes[ps].writeEnd, buffer.ptr, buffer.length); 1: 717: } -: 718: -: 719: function readStreamBuffer(ProcessStream ps; var s8[] buffer): usize -: 720: { 61: 721: return ps in redirects ? read(pipes[ps].readEnd, buffer.ptr, buffer.length) else 0; -: 722: } -: 723: -: 724: function canRead(ProcessStream ps): bool -: 725: { 5833: 726: if ps !in redirects do 1: 727: return false; 5832: 728: var PollFd pf = PollFd.create(pipes[ps].readEnd, POLLIN); 5832: 729: if poll(&pf, 1, 0) == -1 do 0: 730: onProcessError(this, ProcessError.pollFail); 5832: 731: return (pf.revents & POLLIN) == POLLIN; -: 732: } -: 733: -: 734: function readStream(ProcessStream ps): s8[+] -: 735: { -: 736: var s8[+] result; 58: 737: if ps in redirects do -: 738: { -: 739: var usize p; 58: 740: var usize n = 4096; -: 741: @noinit var s8[4096] buffer; 58: 742: while n == 4096 do -: 743: { 59: 744: n = readStreamBuffer(ps, buffer[]); 59: 745: if n do -: 746: { 59: 747: result.length += n; 59: 748: result[p .. $] = buffer[0 .. n]; 59: 749: p += n; -: 750: } -: 751: } -: 752: } 58: 753: return result; -: 754: } -: 755: -: 756: function execute() -: 757: { 340: 758: cleanup(); 340: 759: foreach const ProcessStream ps in ProcessStream do 1020: 760: if ps in redirects do -: 761: { 677: 762: if pipe(pipes[ps]) == -1 && onProcessError do 0: 763: return onProcessError(this, (ProcessError.pipeInFail + ps): ProcessError); -: 764: } -: 765: 340: 766: pid = fork(); 340: 767: if pid == -1 do 0: 768: return onProcessError(this, ProcessError.forkFail); -: 769: 340: 770: if pid == 0 do -: 771: { 0: 772: if ProcessStream.inp in redirects do -: 773: { 0: 774: close(pipes[ProcessStream.inp].writeEnd); 0: 775: dup2(pipes[ProcessStream.inp].readEnd, STDIN_FILENO); -: 776: } 0: 777: if ProcessStream.out in redirects do -: 778: { 0: 779: close(pipes[ProcessStream.out].readEnd); 0: 780: dup2(pipes[ProcessStream.out].writeEnd, STDOUT_FILENO); -: 781: } 0: 782: if ProcessStream.err in redirects do -: 783: { 0: 784: close(pipes[ProcessStream.err].readEnd); 0: 785: dup2(pipes[ProcessStream.err].writeEnd, STDERR_FILENO); -: 786: } -: 787: 0: 788: execv(executable, (executable ~ arguments ~ null:s8*).ptr); 0: 789: if onProcessError do 0: 790: onProcessError(this, ProcessError.execvFail); -: 791: assert(0); -: 792: } 340: 793: } -: 794: -: 795: function tryWait(): bool -: 796: { -: 797: var s32 status; 7397: 798: const s32 r = waitpid(pid, &status, WNOHANG); 7397: 799: if r == 0 do 7058: 800: return false; 339: 801: if r == pid do -: 802: { 339: 803: terminated = true; 339: 804: exitCode = 0; 339: 805: if WIFEXITED(status) do 328: 806: exitCode = WEXITSTATUS(status); 11: 807: else do if WIFSIGNALED(status) do 11: 808: exitCode = -WTERMSIG(status); 339: 809: return true; -: 810: } 0: 811: terminated = true; 0: 812: if onProcessError do 0: 813: onProcessError(this, ProcessError.waitFail); 0: 814: return false; -: 815: } -: 816: -: 817: function wait(): bool -: 818: { -: 819: var bool result; 2: 820: while !terminated do 4481: 821: result = tryWait(); 2: 822: return result; -: 823: } -: 824: -: 825: function waitAndRead(s8[+]* stdOut; s8[+]* stdErr): s32 -: 826: { -: 827: function readOutAndErr() -: 828: { 2916: 829: if out in redirects && stdOut && canRead(ProcessStream.out) do 54: 830: *stdOut ~= readStream(ProcessStream.out); 2916: 831: if err in redirects && stdErr && canRead(ProcessStream.err) do 4: 832: *stdErr ~= readStream(ProcessStream.err); 2916: 833: } -: 834: 337: 835: var TimeSpec ts = (0:s64, 1000_000:s64); 337: 836: while true do -: 837: { 2916: 838: if tryWait() do 337: 839: break; 2579: 840: readOutAndErr(); 2579: 841: nanosleep(&ts); -: 842: } 337: 843: readOutAndErr(); 337: 844: return exitCode; -: 845: } -: 846: -: 847:} -: 848: -: 849:@unittest function testEcho() -: 850:{ -: 851: var Process p; -: 852: p.executable = "/usr/bin/echo"; -: 853: p.arguments ~= "hello world"; -: 854: p.redirects += out; -: 855: p.execute(); -: 856: p.wait(); -: 857: assert(p.terminated); -: 858: assert(p.exitCode == 0); -: 859: -: 860: var s8[+] r; -: 861: r.length = 64; -: 862: const auto len = p.readStreamBuffer(ProcessStream.out, r[]); -: 863: assert(r[0 .. len] == "hello world\n"); -: 864:} -: 865: -: 866:@unittest function testCantRead() -: 867:{ -: 868: var Process p; -: 869: p.executable = "/usr/bin/echo"; -: 870: p.arguments ~= "no redir"; -: 871: p.execute(); -: 872: assert(!p.canRead(ProcessStream.out)); -: 873:} -: 874: -: 875:@unittest function testWc() -: 876:{ -: 877: var Process p; -: 878: p.executable = "/usr/bin/wc"; -: 879: p.arguments ~= "-w"; -: 880: p.redirects = [inp, out]; -: 881: p.execute(); -: 882: p.writeStreamBuffer(ProcessStream.inp, "first second third"); -: 883: p.closeStream(ProcessStream.inp); -: 884: p.wait(); -: 885: assert(p.terminated); -: 886: assert(p.exitCode == 0); -: 887: -: 888: var s8[+] r; -: 889: r.length = 64; -: 890: const auto len = p.readStreamBuffer(ProcessStream.out, r[]); -: 891: assert(r[0 .. len] == "3\n"); -: 892:} -: 893: -: 894:function readInput(): s8[+] -: 895:{ -: 896: @return var s8[+] result; -: 897: @noinit var s8[512] buffer; 2: 898: while true do -: 899: { 2: 900: const auto i = read(STDIN_FILENO, buffer.ptr, buffer.length); 2: 901: if i == -1 do 0: 902: ErrorAndExit1("input stream error"); 2: 903: result ~= buffer[0 .. i]; 2: 904: if i != buffer.length do 2: 905: break; -: 906: } 2: 907: return result; -: 908:} -: 909: -: 910:enum OptionType : u8 -: 911:{ -: 912: boolData, -: 913: boolHandler, -: 914: stringData, -: 915: stringHandler, -: 916:} -: 917: -: 918:struct OptionHandler -: 919:{ -: 920: -: 921:protection(private) -: 922: -: 923: struct Descriptor -: 924: { -: 925: var s8[] longIdent; -: 926: var u8* dataOrHandler; -: 927: var s8 shortIdent; -: 928: var OptionType type; -: 929: -: 930: function tryArgument(s8[] arg): bool -: 931: { 3187: 932: const auto alen = arg.length; 3187: 933: if shortIdent != 0 && alen >= 2 && 977: 934: arg.ptr[0] == "-" && arg.ptr[1] == shortIdent do -: 935: { 54: 936: processValue(arg.ptr[2 .. alen], false); 54: 937: return true; -: 938: } 3133: 939: else do if longIdent.length && arg.startsWith("--") && 1955: 940: alen >= longIdent.length + 2 && arg[2 .. longIdent.length + 2] == longIdent do -: 941: { 308: 942: processValue(arg[longIdent.length + 2 .. $], true); 308: 943: return true; -: 944: } 2825: 945: return false; -: 946: } -: 947: -: 948: static function getBoolValue(s8[] value): bool -: 949: { 54: 950: if value.length == 0 do 46: 951: return true; 24: 952: switch value do -: 953: { 3: 954: on "true" do return true; 5: 955: on "false" do return false; 0: 956: else do ErrorAndExit1("invalid bool argument, expected `true` or `false`"); -: 957: } -: 958: assert(0); -: 959: } -: 960: -: 961: static function isStrValue(s8[] value): bool -: 962: { 308: 963: if value.length != 0 do 308: 964: return true; 0: 965: ErrorAndExit1("error, empty string argument"); -: 966: assert(0); -: 967: } -: 968: -: 969: function processValue(s8[] arg; bool fromLong) -: 970: { 362: 971: const auto alen = arg.length; 362: 972: if fromLong do -: 973: { 308: 974: if alen && arg.ptr[0] != "=" do 0: 975: return ErrorAndExit1("missing `=` in long option"); 308: 976: if alen do 280: 977: arg = arg.ptr[1 .. alen]; -: 978: } 362: 979: if !alen && type in [OptionType.stringData, OptionType.stringHandler] do 0: 980: return ErrorAndExit1("expected string following option"); 362: 981: switch type do -: 982: { -: 983: on boolData do -: 984: { 39: 985: var bool* b = dataOrHandler:bool*; 39: 986: *b = getBoolValue(arg); -: 987: } -: 988: on boolHandler do -: 989: { 15: 990: var auto b = dataOrHandler:BoolFun*; 15: 991: hasErrors |= b(getBoolValue(arg)); -: 992: } -: 993: on stringData do -: 994: { 50: 995: var s8[+]* s = dataOrHandler:s8[+]*; 50: 996: if isStrValue(arg) do 50: 997: *s = arg; -: 998: } -: 999: on stringHandler do -:1000: { 258:1001: var auto s = dataOrHandler:TextFun*; 258:1002: if isStrValue(arg) do 258:1003: hasErrors |= s(arg); -:1004: } -:1005: } 362:1006: } -:1007: } -:1008: -:1009: static var Descriptor[+] descriptors; -:1010: -:1011: @destructor static function destroy() -:1012: { 374:1013: reset(); 374:1014: } -:1015: -:1016: static function processArgument(s8[] arg) -:1017: { 363:1018: foreach var Descriptor d in descriptors do 3187:1019: if d.tryArgument(arg) do 362:1020: return; 0:1021: ErrorAndExit1(("unknow option : " ~ arg ~ "\0").ptr); 0:1022: } -:1023: -:1024: static function reset() -:1025: { 374:1026: descriptors.decref; 374:1027: } -:1028: -:1029:protection(public) -:1030: -:1031: static var bool hasErrors; -:1032: -:1033: /// The type of the generic option handler. Must return `true` on error, else `false` -:1034: alias GenericFun = function(s8[] arg; s32 index; var bool isHandled): bool; -:1035: /// The type of a bool option handler. Must return `true` on error, else `false` -:1036: alias BoolFun = function(bool value): bool; -:1037: /// The type of a text option handler. Must return `true` on error, else `false` -:1038: alias TextFun = function(s8[] value): bool; -:1039: -:1040: static function add[T](const s8 shortIdent; const s8[] longIdent; T handler) -:1041: { 11596:1042: const auto h = handler:u8*; -:1043: if echo(is, T, TextFun*) do 5610:1044: descriptors ~= (longIdent, h, shortIdent, OptionType.stringHandler); -:1045: else do if echo(is, T, s8[+]*) do 1122:1046: descriptors ~= (longIdent, h, shortIdent, OptionType.stringData); -:1047: else do if echo(is, T, BoolFun*) do 1122:1048: descriptors ~= (longIdent, h, shortIdent, OptionType.boolHandler); -:1049: else do if echo(is, T, bool*) do 3742:1050: descriptors ~= (longIdent, h, shortIdent, OptionType.boolData); -:1051: else do static assert(0); 11596:1052: } -:1053: -:1054: static function processArguments(s32 argc; s8** argv; GenericFun* genricHandler = null) -:1055: { 379:1056: foreach const s32 i in 0 .. argc do -:1057: { -:1058: var bool handled; 931:1059: const auto a = *(argv + i); 931:1060: const auto s = a[0 .. strlen(a)]; 931:1061: if genricHandler do 919:1062: hasErrors |= genricHandler(s, i, handled); 931:1063: if !handled do 362:1064: processArgument(s); -:1065: } 378:1066: } -:1067:} -:1068: -:1069:@unittest function testOptionHandler1() -:1070:{ -:1071: var bool b; -:1072: var bool c; -:1073: OptionHandler.add("b", "bee", &b); -:1074: OptionHandler.add("c", "cee", &c); -:1075: OptionHandler.processArguments(2, ["-ctrue", "-btrue"].ptr); -:1076: assert(b); -:1077: assert(c); -:1078: OptionHandler.processArguments(2, ["-cfalse", "-bfalse"].ptr); -:1079: assert(!b); -:1080: assert(!c); -:1081: OptionHandler.processArguments(4, ["-c", "-cfalse", "-ctrue", "-b"].ptr); -:1082: assert(b); -:1083: assert(c); -:1084: OptionHandler.processArguments(2, ["-cfalse", "-bfalse"].ptr); -:1085: assert(!b); -:1086: assert(!c); -:1087: OptionHandler.processArguments(2, ["--cee", "--bee"].ptr); -:1088: assert(b); -:1089: assert(c); -:1090:} -:1091: -:1092:struct Timer -:1093:{ -:1094:protection(private) -:1095: -:1096: static var u64 nt0; -:1097: -:1098: static function nanosNow(): u64 -:1099: { -:1100: @noinit var TimeSpec ts; 24:1101: if clock_gettime(CLOCK_MONOTONIC, &ts) == -1 do 0:1102: ErrorAndExit1("timer failure"); 24:1103: return ts.sec * 1000000000 + ts.nsec; -:1104: } -:1105: -:1106:protection(public) -:1107: -:1108: static function start() -:1109: { 6:1110: nt0 = nanosNow(); 6:1111: } -:1112: -:1113: static function peekString(): s8[+] -:1114: { 18:1115: var u64 nt1 = nanosNow(); 18:1116: var u64 ntd = nt1 - nt0; -:1117: 18:1118: var u64 min = ntd / 60000000000; 18:1119: ntd -= min * 60000000000; 18:1120: var u64 sec = ntd / 1000000000; 18:1121: ntd -= sec * 1000000000; 18:1122: var u64 msec = ntd / 1000000; -:1123: -:1124: @noinit var s8[128] result; 18:1125: snprintf(result.ptr, result.length, "%llu min(s), %llu sec(s), %llu msec(s)", min, sec, msec); -:1126: 18:1127: nt0 = nt1; // nanosNow() to exclude snprintf time 18:1128: return result; -:1129: } -:1130:} -:1131: -:1132:@unittest function testTimer() -:1133:{ -:1134: @foreign function rand(): s32; -:1135: -:1136: Timer.start(); -:1137: foreach var auto i in 0 .. 100 do rand(); -:1138: printf("peek 1 = %s\n", Timer.peekString().ptr); -:1139: foreach var auto i in 0 .. 10000 do rand(); -:1140: printf("peek 2 = %s\n", Timer.peekString().ptr); -:1141: foreach var auto i in 0 .. 200000 do rand(); -:1142: printf("peek 3 = %s\n", Timer.peekString().ptr); -:1143:} -:1144: -:1145:/** -:1146: * Returns: The diagnostic string for the exit status passed as parameter. -:1147: */ -:1148:function prettyExitStatus(s32 exitStatus): s8[+] -:1149:{ -:1150: @return var s8[+] result; 214:1151: if exitStatus < 0 do -:1152: { 60:1153: switch -exitStatus do -:1154: { 1:1155: on 1 do result = "1 (SIGHUP)"; 1:1156: on 2 do result = "2 (SIGINT)"; 1:1157: on 3 do result = "3 (SIGQUIT)"; 12:1158: on 4 do result = "4 (SIGILL)"; 1:1159: on 5 do result = "5 (SIGTRAP)"; 1:1160: on 6 do result = "6 (SIGABRT)"; 1:1161: on 7 do result = "7 (SIGEMT)"; 1:1162: on 8 do result = "8 (SIGFPE)"; 1:1163: on 9 do result = "9 (SIGKILL)"; 1:1164: on 10 do result = "10 (SIGBUS)"; 1:1165: on 11 do result = "11 (SIGSEGV)"; 1:1166: on 12 do result = "12 (SIGSYS)"; 1:1167: on 13 do result = "13 (SIGPIPE)"; 1:1168: on 14 do result = "14 (SIGALRM)"; 1:1169: on 15 do result = "15 (SIGTERM)"; 1:1170: on 16 do result = "16 (SIGUSR1)"; 1:1171: on 17 do result = "17 (SIGUSR2)"; 1:1172: on 18 do result = "18 (SIGCHLD)"; 1:1173: on 19 do result = "19 (SIGPWR)"; 1:1174: on 20 do result = "20 (SIGWINCH)"; 1:1175: on 21 do result = "21 (SIGURG)"; 1:1176: on 22 do result = "22 (SIGPOLL)"; 1:1177: on 23 do result = "23 (SIGSTOP)"; 1:1178: on 24 do result = "24 (SIGTSTP)"; 1:1179: on 25 do result = "25 (SIGCONT)"; 1:1180: on 26 do result = "26 (SIGTTIN)"; 1:1181: on 27 do result = "27 (SIGTTOU)"; 1:1182: on 28 do result = "28 (SIGVTALRM)"; 1:1183: on 29 do result = "29 (SIGPROF)"; 1:1184: on 30 do result = "30 (SIGXCPU)"; 1:1185: on 31 do result = "31 (SIGXFSZ)"; 1:1186: on 32 do result = "32 (SIGWAITING)"; 1:1187: on 33 do result = "33 (SIGLWP)"; 1:1188: on 34 do result = "34 (SIGAIO)"; 15:1189: else do {} -:1190: } -:1191: } 214:1192: if !result.length do -:1193: { 169:1194: result = u32ToString(exitStatus); 169:1195: if exitStatus > 0 do 2:1196: result ~= " (Program-defined exit status)"; 167:1197: else do if exitStatus < 0 do 15:1198: result ~= " (undeterminated meaning)"; -:1199: else do 152:1200: result ~= " (success)"; -:1201: } 214:1202: result ~= "\0"; 214:1203: return result; -:1204:} -:1205: -:1206:@unittest function coverPrettyExitStatus() -:1207:{ -:1208: foreach const s32 i in 0 .. 50 do -:1209: var auto es = prettyExitStatus(-i); -:1210:} -:1211: -:1212:/// A `T` Appender with linear growth by `AllocBy` (num T) -:1213:struct Appender[T, AllocBy] -:1214:{ -:1215:protection (private) -:1216: -:1217: struct Items -:1218: { -:1219: var T* ptr; -:1220: var usize length; -:1221: } -:1222: var Items items; -:1223: var usize reserved; -:1224: -:1225:protection (public) -:1226: -:1227: @destructor function destroy() -:1228: { 128735:1229: free(items.ptr:u8*); 128735:1230: } -:1231: -:1232: function append(const T item) -:1233: { 332942:1234: if !reserved do -:1235: { 2155:1236: items.length += reserved = AllocBy; 2155:1237: items.ptr = realloc(items.ptr:u8*, items.length * T.sizeof):T*; -:1238: } 332942:1239: const auto i = items.length - reserved; 332942:1240: items.ptr[i] = item; 332942:1241: reserved--; 332942:1242: } -:1243: -:1244: function appendN(const T[] inp) -:1245: { 83935:1246: if !reserved do -:1247: { 63308:1248: items.length += reserved = AllocBy; 63308:1249: items.ptr = realloc(items.ptr:u8*, items.length * T.sizeof):T*; -:1250: } 83935:1251: const auto ilen = inp.length; 83935:1252: const auto i = items.length - reserved; 83935:1253: if ilen > reserved do -:1254: { 4:1255: reserved += ilen; 4:1256: items.length += ilen; 4:1257: items.ptr = realloc(items.ptr:u8*, items.length * T.sizeof):T*; -:1258: } 83935:1259: items.ptr[i .. i + ilen] = inp; 83935:1260: reserved -= ilen; 83935:1261: } -:1262: -:1263: function shrink() -:1264: { 1:1265: reserved++; 1:1266: } -:1267: -:1268: @operator($) function length(): usize -:1269: { 100517:1270: return items.length - reserved; -:1271: } -:1272: -:1273: @operator(a[b]) function item(const usize index): T -:1274: { 258421:1275: return items.ptr[index]; -:1276: } -:1277: -:1278: function array(): T[+] -:1279: { 63662:1280: return items.ptr[0 .. length()]; -:1281: } -:1282:} -:1283: -:1284:@unittest function testLinearAppender() -:1285:{ -:1286: var Appender:[u8*, 4] eapp; -:1287: eapp.append(null); -:1288: assert(eapp.length() == 1); -:1289: assert(eapp.reserved == 3); -:1290: eapp.append(null); -:1291: eapp.append(null); -:1292: eapp.append(null); -:1293: assert(eapp.length() == 4); -:1294: assert(eapp.reserved == 0); -:1295: eapp.append(null); -:1296: eapp.append(null); -:1297: eapp.append(null); -:1298: assert(eapp.length() == 7); -:1299: assert(eapp.reserved == 1); -:1300: eapp.append(null); -:1301: assert(eapp.length() == 8); -:1302: assert(eapp.reserved == 0); -:1303:} -:1304: -:1305:struct StackAppender[SA_STATIC_LEN, T] -:1306:{ -:1307: @noinit var T[SA_STATIC_LEN] stackPart; -:1308: var T[+] heapPart; -:1309: var usize stackLength; -:1310: var bool reclaimed; -:1311: -:1312: @inline(true) function append(T item) -:1313: { 57468:1314: if stackLength < SA_STATIC_LEN do 55967:1315: stackPart.ptr[stackLength++] = item; 1501:1316: else do heapPart ~= item; 57468:1317: } -:1318: -:1319: function reclaim(): T[+] -:1320: { 20126:1321: const usize hlen = heapPart.length; 20126:1322: @return var T[+] result = (new T[+])(stackLength + hlen); 20126:1323: result.ptr[0 .. stackLength] = stackPart.ptr[0 .. stackLength]; 20126:1324: if hlen do 19:1325: result.ptr[stackLength .. stackLength + hlen] = heapPart[]; 20126:1326: reclaimed = true; 20126:1327: return result; -:1328: } -:1329: -:1330: @destructor function destroy() -:1331: { 26512:1332: if !reclaimed do -:1333: { -:1334: if echo(isPointer, T) do -:1335: { 6386:1336: foreach var auto d in stackPart[0 .. stackLength] do 31:1337: d.free(); 6386:1338: foreach var auto d in heapPart do 2:1339: d.free(); -:1340: } -:1341: } 26512:1342: heapPart.decref; 26512:1343: } -:1344:} -:1345: -:1346:@unittest function coverFreeHeapPart() -:1347:{ -:1348: static var s32 cnt; -:1349: class A -:1350: { -:1351: @destructor function free() -:1352: { -:1353: cnt++; -:1354: } -:1355: } -:1356: -:1357: var A*[6] elems; -:1358: foreach const auto i in 0 .. elems.length do -:1359: elems[i] = new A; -:1360: { -:1361: alias OApp = apply(StackAppender, 4, A*); -:1362: var OApp oapp; -:1363: foreach var auto e in elems do -:1364: oapp.append(e); -:1365: } -:1366: assert(cnt == 6); -:1367: foreach var auto e in elems do -:1368: delete e; -:1369: -:1370:} <<<<<< EOF # path=src/styx/backend.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/backend.sx -: 1:unit styx.backend; -: 2: -: 3:version llvm do -: 4:{ -: 5: @private import -: 6: styx.ast.base, -: 7: styx.ast.declarations, -: 8: styx.backend.irgen, -: 9: styx.backend.link, -:10: ; -:11: -:12: alias linkExecutable = styx.backend.link.linkExecutable; -:13: alias linkArchive = styx.backend.link.linkArchive; -:14: -:15: /// Produce the intermediate representation of a whole unit. -:16: /// Returns: `true` on sucess, `false` otherwise. -:17: function produceIR(UnitDeclaration* node): bool -:18: { -:19: var LLVMIrGen lig; 282:20: lig.visitDeclaration(node); 282:21: return lig.success(); -:22: } -:23:} -:24:else do -:25:{ -:26: @private import -:27: styx.ast.declarations, -:28: ; -:29: -:30: /// -:31: function produceIR(UnitDeclaration* node): bool -:32: { -:33: return true; -:34: } -:35:} <<<<<< EOF # path=src/styx/lexer.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/lexer.sx -: 1:unit styx.lexer; -: 2: -: 3:@private import -: 4: system, styx.position, styx.token, styx.session; -: 5: -: 6:struct Lexer -: 7:{ -: 8: -: 9:protection (private) -: 10: -: 11: var s8[+] fname; -: 12: var s8[+] textCont; -: 13: var s8[] textView; -: 14: var s8* nexttPtr; -: 15: var Position frontPos; -: 16: var Position nexttPos; -: 17: var TokenType nexttType; -: 18: var bool engaged; -: 19: var Token* frontt; -: 20: var Token* nextt; -: 21: var bool skipComments; -: 22: -: 23: function error(const s8[] message) -: 24: { 52: 25: Session.error(fname, frontPos, message.ptr); 52: 26: } -: 27: -: 28: // Engage next token based on a possible type. -: 29: function engageNext(TokenType type) -: 30: { 402261: 31: nexttPtr = textView.ptr; 402261: 32: nexttPos = frontPos; 402261: 33: nexttType = type; 402261: 34: engaged = true; 402261: 35: } -: 36: -: 37: // Finalize a new token, as engaged. -: 38: function validateToken() -: 39: { 397488: 40: nextt = (new Token).create(nexttPtr[0 .. textView.ptr-nexttPtr], nexttPos.line, nexttPos.column, nexttType); 397488: 41: nextt.prev = frontt; 397488: 42: engaged = false; 397488: 43: } -: 44: -: 45: // Finalize a new token, fix the engagement. -: 46: @inline function fixAndValidateToken(TokenType type) -: 47: { 1337: 48: nextt = (new Token).create(nexttPtr[0 .. textView.ptr-nexttPtr], nexttPos.line, nexttPos.column, type); 1337: 49: nextt.prev = frontt; 1337: 50: engaged = false; 1337: 51: } -: 52: -: 53: // current 2538197: 54: @inline function frontChar(): s8 { return textView[0]; } -: 55: -: 56: // next ascii, synchronizes column. -: 57: @inline function advance() -: 58: { 1749297: 59: textView = textView.ptr[1 .. textView.length]; 1749297: 60: ++frontPos.column; 1749297: 61: } -: 62: -: 63: // advance by two ascii, -: 64: // should be protected by canLookup/safeLookup -: 65: @inline function advanceTwice() -: 66: { 10029: 67: textView = textView.ptr[2 .. textView.length]; 10029: 68: frontPos.column += 2; 10029: 69: } -: 70: -: 71: @inline function canLookupChar(): bool -: 72: { 38095: 73: return textView.length > 1; -: 74: } -: 75: -: 76: @inline function safeLookupChar(): s8* -: 77: { 30332: 78: return textView.length > 1 ? &textView.ptr[1] else null; -: 79: } -: 80: -: 81: @inline function canLookup2Char(): bool -: 82: { 1131: 83: return textView.length > 2; -: 84: } -: 85: -: 86: @inline function lookupChar(): s8* -: 87: { 38758: 88: return &textView.ptr[1]; -: 89: } -: 90: -: 91: // Must be called when a sub-lexer finds a line ending. -: 92: @inline function processlineEnding() -: 93: { 81177: 94: if frontChar() == "\r" do 2: 95: advance(); 81177: 96: if frontChar() == "\n" do -: 97: { 81177: 98: advance(); 81177: 99: ++frontPos.line; 81177: 100: frontPos.column = 1; -: 101: } 81177: 102: } -: 103: -: 104: static function isHexDigit(const s8 c): bool -: 105: { 347: 106: switch c do -: 107: { -: 108: on "0" .. "9", "a" .. "f", "A" .. "F" do 345: 109: return true; -: 110: else do 2: 111: return false; -: 112: } -: 113: } -: 114: -: 115: function lexStringEscape(): bool -: 116: { 452: 117: assert(frontChar() == "\\"); 452: 118: if !canLookupChar() do 1: 119: return false; 451: 120: advance(); 451: 121: switch frontChar() do -: 122: { -: 123: on "0", "a", "b", "f", "r", "t", "n", "v", "\"", "\\" do -: 124: { 413: 125: advance(); 413: 126: return true; -: 127: } -: 128: on "x" do -: 129: { 37: 130: advance(); 37: 131: if isHexDigit(frontChar()) do -: 132: { 36: 133: advance(); 36: 134: if isHexDigit(frontChar()) do -: 135: { 36: 136: advance(); 36: 137: return true; -: 138: } -: 139: } 1: 140: return false; -: 141: } 1: 142: else do return false; -: 143: } -: 144: } -: 145: -: 146: function checkBiDi() -: 147: { 4: 148: advance(); 4: 149: var auto c1 = frontChar():u8; 4: 150: advance(); 4: 151: var auto c2 = frontChar():u8; 4: 152: advance(); 4: 153: if (c1 == 0x80 && ((0x8A <= c2 && c2 <= 0x8F) || (c2 == 0xAD) || (c2 == 0xAE))) || 1: 154: (c1 == 0x81 && 0xA6 <= c2 && c2 <= 0xA9) do -: 155: { 4: 156: error("BiDi control characters are not allowed"); -: 157: } 4: 158: } -: 159: -: 160: function lexStringLiteral() -: 161: { 3735: 162: advance(); 3735: 163: engageNext(TokenType.stringLiteral); 3735: 164: while true do -: 165: { 83815: 166: if textView.length == 0 do -: 167: { 5: 168: error("unterminated string literal"); 5: 169: fixAndValidateToken(TokenType.invalid); 5: 170: return; -: 171: } 83810: 172: switch frontChar() do -: 173: { -: 174: on 0 do -: 175: { 1: 176: error("null character encountered inside a string literal"); 1: 177: advance(); 1: 178: fixAndValidateToken(TokenType.invalid); 1: 179: return; -: 180: } -: 181: on "\\" do -: 182: { 452: 183: if lexStringEscape() do 449: 184: continue; 3: 185: error(`invalid escape`); 3: 186: fixAndValidateToken(TokenType.invalid); 3: 187: return; -: 188: } -: 189: on "\"" do -: 190: { 3726: 191: validateToken(); 3726: 192: advance(); 3726: 193: return; -: 194: } -: 195: on 0xE2:s8 do -: 196: { 3: 197: canLookup2Char() ? checkBiDi() else advance(); -: 198: } 429: 199: on "\r", "\n" do processlineEnding(); 79199: 200: else do advance(); -: 201: } -: 202: } -: 203: } -: 204: -: 205: function lexRawStringLiteral() -: 206: { 1295: 207: advance(); 1295: 208: engageNext(TokenType.rawStringLiteral); 1295: 209: while true do -: 210: { 91579: 211: if textView.length == 0 do -: 212: { 1: 213: error("unterminated raw string literal"); 1: 214: fixAndValidateToken(TokenType.invalid); 1: 215: return; -: 216: } 91578: 217: switch frontChar() do -: 218: { -: 219: on 0 do -: 220: { 1: 221: error("null character encountered inside a raw string literal"); 1: 222: advance(); 1: 223: fixAndValidateToken(TokenType.invalid); 1: 224: return; -: 225: } -: 226: on "`" do -: 227: { 1293: 228: validateToken(); 1293: 229: advance(); 1293: 230: return; -: 231: } -: 232: on 0xE2:s8 do -: 233: { 1: 234: canLookup2Char() ? checkBiDi() else advance(); 1: 235: continue; -: 236: } 4674: 237: on "\r", "\n" do processlineEnding(); 85609: 238: else do advance(); -: 239: } -: 240: } -: 241: } -: 242: -: 243: function lexLineComment() -: 244: { 3125: 245: engageNext(TokenType.lineComment); 3125: 246: advanceTwice(); 3125: 247: while true do -: 248: { 108350: 249: if textView.length == 0 do -: 250: { 2: 251: validateToken(); 2: 252: return; -: 253: } 108348: 254: switch frontChar() do -: 255: { -: 256: on 0 do -: 257: { 1: 258: error("null character encountered inside a comment"); 1: 259: advance(); 1: 260: fixAndValidateToken(TokenType.invalid); 1: 261: return; -: 262: } -: 263: on "\r", "\n" do -: 264: { 3122: 265: if skipComments do -: 266: { 3116: 267: processlineEnding(); 3116: 268: scanNext(); -: 269: } -: 270: else do -: 271: { 6: 272: validateToken(); 6: 273: processlineEnding(); -: 274: } 3122: 275: return; -: 276: } 105225: 277: else do advance(); -: 278: } -: 279: } -: 280: } -: 281: -: 282: function lexStarComment() -: 283: { 328: 284: engageNext(TokenType.starComment); 328: 285: advanceTwice(); 328: 286: while true do -: 287: { 47083: 288: if textView.length == 0 do -: 289: { 1: 290: error("unterminated star comment"); 1: 291: return fixAndValidateToken(TokenType.invalid); -: 292: } 47082: 293: switch frontChar() do -: 294: { -: 295: on 0 do -: 296: { 2: 297: error("null character encountered inside a star comment"); 2: 298: advance(); 2: 299: return fixAndValidateToken(TokenType.invalid); -: 300: } -: 301: on "*" do -: 302: { 926: 303: if canLookupChar() && *lookupChar() == "/" do -: 304: { 325: 305: advanceTwice(); 325: 306: skipComments ? scanNext() else validateToken(); 325: 307: return; -: 308: } 601: 309: advance(); -: 310: } -: 311: on 0xE2:s8 do -: 312: { 1: 313: canLookup2Char() ? checkBiDi() else advance(); 1: 314: continue; -: 315: } 1069: 316: on "\r", "\n" do processlineEnding(); 45084: 317: else do advance(); -: 318: } -: 319: } -: 320: } -: 321: -: 322: function lexHexLiteral() -: 323: { 275: 324: if textView.length == 0 do -: 325: { 1: 326: error("unterminated hex literal"); 1: 327: return fixAndValidateToken(TokenType.invalid); -: 328: } 274: 329: const auto c = frontChar(); 274: 330: if !isHexDigit(c) do -: 331: { 1: 332: error("expected an hexadecimal digit to start a hex literal"); 1: 333: advance(); 1: 334: return fixAndValidateToken(TokenType.invalid); -: 335: } 273: 336: advance(); 273: 337: while true do -: 338: { 960: 339: if textView.length == 0 do 4: 340: return validateToken(); 956: 341: switch frontChar() do -: 342: { 687: 343: on "0".."9", "a".. "f", "A".."F", "_" do advance(); -: 344: on "g".. "z", "G".."Z" do -: 345: { 2: 346: error("invalid hexadecimal digit"); 2: 347: advance(); 2: 348: return fixAndValidateToken(TokenType.invalid); -: 349: } 267: 350: else do return validateToken(); -: 351: } -: 352: } -: 353: } -: 354: -: 355: function lexBinLiteral() -: 356: { 5: 357: if textView.length == 0 do -: 358: { 1: 359: error("unterminated binary literal"); 1: 360: return fixAndValidateToken(TokenType.invalid); -: 361: } 4: 362: const auto c = frontChar(); 4: 363: if c != "0" && c != "1" do -: 364: { 1: 365: error("expected `0` or `1` to start a binary literal"); 1: 366: advance(); 1: 367: return fixAndValidateToken(TokenType.invalid); -: 368: } 3: 369: while true do -: 370: { 22: 371: if textView.length == 0 do 1: 372: return validateToken(); 21: 373: switch frontChar() do -: 374: { 19: 375: on "0", "1", "_" do advance(); 2: 376: else do return validateToken(); -: 377: } -: 378: } -: 379: } -: 380: -: 381: function lexIntegerLiteral() -: 382: { 12210: 383: engageNext(TokenType.intLiteral); 12210: 384: while true do -: 385: { 30317: 386: if textView.length == 0 do 6: 387: return validateToken(); 30311: 388: switch frontChar() do -: 389: { -: 390: on 0 do -: 391: { 1: 392: error("null character encountered inside an int literal"); 1: 393: advance(); 1: 394: return fixAndValidateToken(TokenType.invalid); -: 395: } 18107: 396: on "0".."9", "_" do advance(); -: 397: on "a".."z", "A".."Z" do -: 398: { 1: 399: error("invalid decimal digit"); 1: 400: advance(); 1: 401: return fixAndValidateToken(TokenType.invalid); -: 402: } -: 403: on "." do -: 404: { 205: 405: const auto cc = safeLookupChar(); 205: 406: if cc && "0" <= *cc && *cc <= "9" do -: 407: { 134: 408: advance(); 134: 409: return lexFloatingLiteralFractionalPart(); -: 410: } 71: 411: else do return validateToken(); -: 412: } 11997: 413: else do return validateToken(); -: 414: } -: 415: } -: 416: } -: 417: -: 418: function lexExponent() -: 419: { 4: 420: const auto cc = safeLookupChar(); 4: 421: if cc && (*cc == "+" || *cc == "-") do 2: 422: advance(); 4: 423: advance(); 4: 424: while true do -: 425: { 7: 426: if textView.length == 0 do 1: 427: return fixAndValidateToken(TokenType.floatLiteral); 6: 428: switch frontChar() do -: 429: { -: 430: on 0 do -: 431: { 1: 432: error("null character encountered inside exponent part of a float literal"); 1: 433: advance(); 1: 434: return fixAndValidateToken(TokenType.invalid); -: 435: } 3: 436: on "0".."9" do advance(); 2: 437: else do return fixAndValidateToken(TokenType.floatLiteral); -: 438: } -: 439: } -: 440: } -: 441: -: 442: function lexFloatingLiteralFractionalPart() -: 443: { 134: 444: assert (engaged); 134: 445: while true do -: 446: { 289: 447: if textView.length == 0 do 4: 448: return fixAndValidateToken(TokenType.floatLiteral); 285: 449: switch frontChar() do -: 450: { -: 451: on 0 do -: 452: { 1: 453: error("null character encountered inside a float literal"); 1: 454: advance(); 1: 455: return fixAndValidateToken(TokenType.invalid); -: 456: } 155: 457: on "0".."9", "_" do advance(); 4: 458: on "e", "E" do return lexExponent(); 125: 459: else do return fixAndValidateToken(TokenType.floatLiteral); -: 460: } -: 461: } -: 462: } -: 463: -: 464: function lexIdentifier() -: 465: { 179846: 466: engageNext(TokenType.id); -: 467: var bool oneChar; 179846: 468: const auto isDollar = frontChar() == "$"; 179846: 469: if isDollar do 1220: 470: advance(); 179846: 471: while true do -: 472: { 1152473: 473: if textView.length == 0 do 15: 474: return validateToken(); 1152458: 475: switch frontChar() do -: 476: { -: 477: on 0 do -: 478: { 1: 479: error("null character encountered inside an identifier"); 1: 480: advance(); 1: 481: return fixAndValidateToken(TokenType.invalid); -: 482: } -: 483: on "a".."z", "A".."Z", "0".."9", "_" do -: 484: { 972627: 485: advance(); 972627: 486: oneChar = true; -: 487: } 179830: 488: else do return (isDollar && !oneChar) ? fixAndValidateToken(TokenType.dollar) else validateToken(); -: 489: } -: 490: } -: 491: } -: 492: -: 493: function checkBOM(): bool -: 494: { 2280: 495: if textView.length == 0 do 1: 496: return true; -: 497: 2279: 498: const u8 c0 = frontChar(); 2279: 499: if c0 < 0x80 do -: 500: { 2275: 501: return true; -: 502: } 4: 503: else do if c0 != 0xEF || !canLookup2Char() do -: 504: { 1: 505: error("invalid BOM"); 1: 506: return false; -: 507: } -: 508: 3: 509: advance(); 3: 510: const u8 c1 = frontChar(); 3: 511: advance(); 3: 512: const u8 c2 = frontChar(); 3: 513: advance(); -: 514: 3: 515: if c1 != 0xBB || c2 != 0xBF do -: 516: { 1: 517: return false; -: 518: } 2: 519: frontPos.column = 1; 2: 520: return true; -: 521: } -: 522: -: 523: function skipSheBang() -: 524: { 2280: 525: if textView.length > 1 && *textView.ptr:u16* == 0x2123 do -: 526: { 2: 527: while true do -: 528: { 30: 529: if textView.length == 0 do 1: 530: break; 29: 531: switch frontChar() do -: 532: { 1: 533: on "\r", "\n" do return processlineEnding(); 28: 534: else do advance(); -: 535: } -: 536: } -: 537: } 2279: 538: } -: 539: -: 540: function scanNext() -: 541: { 679543: 542: if !frontt do -: 543: { 2280: 544: if !checkBOM() do 2: 545: textView = textView[0 .. 0]; 2280: 546: skipSheBang(); -: 547: } 679543: 548: if textView.length == 0 do -: 549: { 1977: 550: engageNext(TokenType.eof); 1977: 551: return validateToken(); -: 552: } 677566: 553: switch frontChar() do -: 554: { -: 555: on 0 do -: 556: { -: 557: //warning("null character encountered between two tokens"); 2: 558: advance(); 2: 559: return scanNext(); -: 560: } -: 561: on " " do -: 562: { -: 563: @noinit var usize len; 205395: 564: if frontPos.column == 1 do -: 565: { -: 566: var bool scanned; 53563: 567: while (frontPos.column & 3) == 1 && (len = textView.length) > 3 && *textView.ptr:u32* == 0x20202020 do -: 568: { 101430: 569: textView = textView.ptr[4 .. len]; 101430: 570: frontPos.column += 4; 101430: 571: scanned = true; -: 572: } 53563: 573: if scanned do 53555: 574: return scanNext(); -: 575: } 151840: 576: advance(); 151840: 577: return scanNext(); -: 578: } -: 579: on "\t", "\v", "\f" do -: 580: { 3: 581: advance(); 3: 582: return scanNext(); -: 583: } -: 584: on "\r", "\n" do -: 585: { 71882: 586: processlineEnding(); 71882: 587: return scanNext(); -: 588: } -: 589: on "/" do -: 590: { 7602: 591: if const auto cc = safeLookupChar() do -: 592: { 3800: 593: switch *cc do -: 594: { -: 595: on "/" do 3125: 596: return lexLineComment(); -: 597: on "*" do 328: 598: return lexStarComment(); -: 599: on "=" do -: 600: { 54: 601: engageNext(TokenType.divAss); 54: 602: advanceTwice(); 54: 603: return validateToken(); -: 604: } 293: 605: else do {} -: 606: } -: 607: } 294: 608: engageNext(TokenType.div); 294: 609: advance(); 294: 610: return validateToken(); -: 611: } 179846: 612: on "a".."z", "A".."Z", "_", "$" do return lexIdentifier(); -: 613: on "0" do -: 614: { 10334: 615: if const auto cc = safeLookupChar() do -: 616: { 5163: 617: const auto dc = *cc; 5163: 618: if "x" == dc || dc == "X" do -: 619: { 275: 620: engageNext(TokenType.hexLiteral); 275: 621: advanceTwice(); 275: 622: return lexHexLiteral(); -: 623: } 4888: 624: else do if "b" == dc || dc == "B" do -: 625: { 5: 626: engageNext(TokenType.binLiteral); 5: 627: advanceTwice(); 5: 628: return lexBinLiteral(); -: 629: } -: 630: } 4887: 631: return lexIntegerLiteral(); -: 632: } 7323: 633: on "1".."9" do return lexIntegerLiteral(); -: 634: on "-" do -: 635: { 3014: 636: if const auto cc = safeLookupChar() do -: 637: { 1505: 638: const auto dc = *cc; 1505: 639: if dc == "-" do -: 640: { 194: 641: engageNext(TokenType.minMin); 194: 642: advanceTwice(); 194: 643: return validateToken(); -: 644: } 1311: 645: else do if dc == "=" do -: 646: { 141: 647: engageNext(TokenType.minusAss); 141: 648: advanceTwice(); 141: 649: return validateToken(); -: 650: } -: 651: } 1172: 652: engageNext(TokenType.minus); 1172: 653: advance(); 1172: 654: return validateToken(); -: 655: } 3735: 656: on "\"" do return lexStringLiteral(); 1295: 657: on "`" do return lexRawStringLiteral(); -: 658: on "&" do -: 659: { 2998: 660: if const auto cc = safeLookupChar() do -: 661: { 1498: 662: const auto dc = *cc; 1498: 663: if dc == "&" do -: 664: { 1030: 665: engageNext(TokenType.andAnd); 1030: 666: advanceTwice(); 1030: 667: return validateToken(); -: 668: } 468: 669: else do if dc == "=" do -: 670: { 11: 671: engageNext(TokenType.ampAss); 11: 672: advanceTwice(); 11: 673: return validateToken(); -: 674: } -: 675: } 458: 676: engageNext(TokenType.amp); 458: 677: advance(); 458: 678: return validateToken(); -: 679: } -: 680: on "|" do -: 681: { 1138: 682: if const auto cc = safeLookupChar() do -: 683: { 567: 684: const auto dc = *cc; 567: 685: if dc == "|" do -: 686: { 501: 687: engageNext(TokenType.orOr); 501: 688: advanceTwice(); 501: 689: return validateToken(); -: 690: } 66: 691: else do if dc == "=" do -: 692: { 11: 693: engageNext(TokenType.pipeAss); 11: 694: advanceTwice(); 11: 695: return validateToken(); -: 696: } -: 697: } 57: 698: engageNext(TokenType.pipe); 57: 699: advance(); 57: 700: return validateToken(); -: 701: } -: 702: on "+" do -: 703: { 5724: 704: if const auto cc = safeLookupChar() do -: 705: { 2861: 706: const auto dc = *cc; 2861: 707: if dc == "+" do -: 708: { 654: 709: engageNext(TokenType.plusPlus); 654: 710: advanceTwice(); 654: 711: return validateToken(); -: 712: } 2207: 713: else do if dc == "=" do -: 714: { 245: 715: engageNext(TokenType.plusAss); 245: 716: advanceTwice(); 245: 717: return validateToken(); -: 718: } -: 719: } 1963: 720: engageNext(TokenType.plus); 1963: 721: advance(); 1963: 722: return validateToken(); -: 723: } -: 724: on "*" do -: 725: { 9863: 726: if canLookupChar() && *lookupChar() == "=" do -: 727: { 15: 728: engageNext(TokenType.mulAss); 15: 729: advance(); -: 730: } -: 731: else do -: 732: { 9848: 733: engageNext(TokenType.mul); -: 734: } 9863: 735: advance(); 9863: 736: return validateToken(); -: 737: } -: 738: on "%" do -: 739: { 78: 740: if canLookupChar() && *lookupChar() == "=" do -: 741: { 6: 742: engageNext(TokenType.modAss); 6: 743: advance(); -: 744: } -: 745: else do -: 746: { 72: 747: engageNext(TokenType.mod); -: 748: } 78: 749: advance(); 78: 750: return validateToken(); -: 751: } -: 752: on "^" do -: 753: { 20: 754: if canLookupChar() && *lookupChar() == "=" do -: 755: { 11: 756: engageNext(TokenType.xorAss); 11: 757: advance(); -: 758: } -: 759: else do -: 760: { 9: 761: engageNext(TokenType.xor); -: 762: } 20: 763: advance(); 20: 764: return validateToken(); -: 765: } -: 766: on "~" do -: 767: { 979: 768: if canLookupChar() && *lookupChar() == "=" do -: 769: { 863: 770: engageNext(TokenType.tidAss); 863: 771: advance(); -: 772: } -: 773: else do -: 774: { 116: 775: engageNext(TokenType.tidle); -: 776: } 979: 777: advance(); 979: 778: return validateToken(); -: 779: } -: 780: on ">" do -: 781: { 512: 782: if canLookup2Char() && lookupChar()[0..2] == ">=" do -: 783: { 6: 784: engageNext(TokenType.rshiftAss); 6: 785: advanceTwice(); -: 786: } 506: 787: else do if canLookupChar() && *lookupChar() == "=" do -: 788: { 132: 789: engageNext(TokenType.greaterEqual); 132: 790: advance(); -: 791: } 374: 792: else do if canLookupChar() && *lookupChar() == ">" do -: 793: { 11: 794: engageNext(TokenType.rShift); 11: 795: advance(); -: 796: } -: 797: else do -: 798: { 363: 799: engageNext(TokenType.greater); -: 800: } 512: 801: advance(); 512: 802: return validateToken(); -: 803: } -: 804: on "<" do -: 805: { 611: 806: if canLookup2Char() && lookupChar()[0..2] == "<=" do -: 807: { 6: 808: engageNext(TokenType.lshiftAss); 6: 809: advanceTwice(); -: 810: } 605: 811: else do if canLookupChar() && *lookupChar() == "=" do -: 812: { 70: 813: engageNext(TokenType.lesserEqual); 70: 814: advance(); -: 815: } 535: 816: else do if canLookupChar() && *lookupChar() == "<" do -: 817: { 10: 818: engageNext(TokenType.lShift); 10: 819: advance(); -: 820: } -: 821: else do -: 822: { 525: 823: engageNext(TokenType.lesser); -: 824: } 611: 825: advance(); 611: 826: return validateToken(); -: 827: } -: 828: on "." do -: 829: { 19950: 830: engageNext(TokenType.dot); 19950: 831: if canLookupChar() && *lookupChar() == "." do -: 832: { 1059: 833: advance(); 1059: 834: if canLookupChar() && *lookupChar() == "." do -: 835: { 97: 836: advanceTwice(); 97: 837: return fixAndValidateToken(TokenType.ellipsis); -: 838: } -: 839: else do -: 840: { 962: 841: advance(); 962: 842: return fixAndValidateToken(TokenType.dotDot); -: 843: } -: 844: } -: 845: else do -: 846: { 18891: 847: advance(); 18891: 848: return validateToken(); -: 849: } -: 850: } -: 851: on "@" do -: 852: { 3609: 853: engageNext(TokenType.at); 3609: 854: advance(); 3609: 855: return validateToken(); -: 856: } -: 857: on ";" do -: 858: { 34178: 859: engageNext(TokenType.semiColon); 34178: 860: advance(); 34178: 861: return validateToken(); -: 862: } -: 863: on "(" do -: 864: { 27781: 865: engageNext(TokenType.leftParen); 27781: 866: advance(); 27781: 867: return validateToken(); -: 868: } -: 869: on ")" do -: 870: { 27686: 871: engageNext(TokenType.rightParen); 27686: 872: advance(); 27686: 873: return validateToken(); -: 874: } -: 875: on "," do -: 876: { 11366: 877: engageNext(TokenType.comma); 11366: 878: advance(); 11366: 879: return validateToken(); -: 880: } -: 881: on ":" do -: 882: { 6242: 883: engageNext(TokenType.colon); 6242: 884: advance(); 6242: 885: return validateToken(); -: 886: } -: 887: on "{" do -: 888: { 10592: 889: engageNext(TokenType.leftCurly); 10592: 890: advance(); 10592: 891: return validateToken(); -: 892: } -: 893: on "}" do -: 894: { 10431: 895: engageNext(TokenType.rightCurly); 10431: 896: advance(); 10431: 897: return validateToken(); -: 898: } -: 899: on "[" do -: 900: { 5655: 901: engageNext(TokenType.leftSquare); 5655: 902: advance(); 5655: 903: return validateToken(); -: 904: } -: 905: on "]" do -: 906: { 5640: 907: engageNext(TokenType.rightSquare); 5640: 908: advance(); 5640: 909: return validateToken(); -: 910: } -: 911: on "!" do -: 912: { 1906: 913: if canLookupChar() && *lookupChar() == "=" do -: 914: { 495: 915: engageNext(TokenType.notEqual); 495: 916: advance(); -: 917: } -: 918: else do -: 919: { 1411: 920: engageNext(TokenType.not); -: 921: } 1906: 922: advance(); 1906: 923: return validateToken(); -: 924: } -: 925: on "?" do -: 926: { 842: 927: if canLookupChar() && *lookupChar() == "=" do -: 928: { 60: 929: engageNext(TokenType.optAss); 60: 930: advance(); -: 931: } -: 932: else do -: 933: { 782: 934: engageNext(TokenType.qmark); -: 935: } 842: 936: advance(); 842: 937: return validateToken(); -: 938: } -: 939: on "=" do -: 940: { 29436: 941: if const auto cc = safeLookupChar() do -: 942: { 14717: 943: const auto dc = *cc; 14717: 944: if dc == "=" do -: 945: { 2963: 946: engageNext(TokenType.equal); 2963: 947: advanceTwice(); 2963: 948: return validateToken(); -: 949: } 11754: 950: else do if dc == ">" do -: 951: { 58: 952: engageNext(ExtendedTokenType.eopLambda); 58: 953: advanceTwice(); 58: 954: return validateToken(); -: 955: } -: 956: } 11697: 957: engageNext(TokenType.ass); 11697: 958: advance(); 11697: 959: return validateToken(); -: 960: } -: 961: else do -: 962: { 21: 963: engageNext(TokenType.invalid); 21: 964: error("invalid input character"); 21: 965: advance(); 21: 966: return validateToken(); -: 967: } -: 968: } -: 969: } -: 970: -: 971:protection (public) -: 972: -: 973: /** -: 974: * Creates a lexer and cache the sliding window -: 975: * -: 976: * Params: -: 977: * filename = The name of the file to lex -: 978: */ -: 979: @constructor function createFromFile(s8[] filename; bool skipComments) -: 980: { 391: 981: textCont = system.fileRead(filename); 391: 982: textView = textCont; 391: 983: fname = filename; 391: 984: frontPos = (1, 1); 391: 985: this.skipComments = skipComments; 391: 986: popFront(); 391: 987: popFront(); 391: 988: } -: 989: -: 990: /** -: 991: * Constructs a lexer from text and cache the sliding window -: 992: * -: 993: * Params: -: 994: * text = The string to parse. -: 995: * filename = For the errors, the name of the file. -: 996: * line = For the errors, the line where the text starts. -: 997: * column = For the errors, the column where the text starts. -: 998: */ -: 999: @constructor function createFromText(s8[] text; s8[] filename = ""; u32 line = 1; u32 column = 1; bool skipComments = true) -:1000: { 908:1001: textCont = text; 908:1002: textView = textCont; 908:1003: fname = filename; 908:1004: frontPos = (line, column); 908:1005: this.skipComments = skipComments; 908:1006: popFront(); 908:1007: popFront(); 908:1008: } -:1009: -:1010: @destructor function destroy() -:1011: { 1299:1012: var auto tt = nextt; 1299:1013: while tt do -:1014: { 398825:1015: var auto t = tt; 398825:1016: tt = tt.prev; 398825:1017: delete t; -:1018: } 1299:1019: fname.decref; 1299:1020: textCont.decref; 1299:1021: } -:1022: -:1023: /// Returns: the front token -:1024: @inline function front(): Token* -:1025: { 397519:1026: return frontt; -:1027: } -:1028: -:1029: /// advance the sliding window -:1030: @inline function popFront() -:1031: { 398825:1032: frontt = nextt; 398825:1033: scanNext(); 398825:1034: } -:1035: -:1036: /// Returns: if EOF is reached -:1037: @inline function empty(): bool -:1038: { 301:1039: return frontt.type == TokenType.eof; -:1040: } -:1041: -:1042: /// Returns: the next token, without moving the front. -:1043: @inline function lookup(): Token* -:1044: { 8311:1045: return nextt; -:1046: } -:1047: -:1048: /// Returns: the stream of tokens as an array. -:1049: function array(): Token*[+] -:1050: { -:1051: var Token*[+] result; 94:1052: while true do -:1053: { 301:1054: result ~= front(); 301:1055: if empty() do 94:1056: break; 207:1057: popFront(); -:1058: } 94:1059: return result; -:1060: } -:1061: -:1062: /// Returns: The name of the associated source file 2522:1063: function filename(): s8[+] {return fname;} -:1064:} -:1065: -:1066:/// -:1067:@unittest function test178() -:1068:{ -:1069: const s32 line = (echo(line) + 2):s32; -:1070: const s8[] source = -:1071: ` unit a.b; -:1072: // comment 1 -:1073: virtual unit c; -:1074: // comment 2 -:1075: virtual unit d; -:1076: // comment 3 -:1077: // comment 4 -:1078: ;;;..... -:1079: `; -:1080: -:1081: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 7, false); -:1082: var Token*[+] toks = lx.array(); -:1083: -:1084: assert(toks.length == 23); -:1085: assert(toks[0].text() == "unit"); -:1086: assert(toks[0].isTokKeyword()); -:1087: assert(toks[0].isTok:[$unit]()); -:1088: assert(toks[1].text() == "a"); -:1089: assert(toks[1].isTok:[id]()); -:1090: assert(toks[2].text() == "."); -:1091: assert(toks[2].isTok:[dot]()); -:1092: assert(toks[3].text() == "b"); -:1093: assert(toks[3].isTok:[id]()); -:1094: assert(toks[4].text() == ";"); -:1095: assert(toks[4].isTok:[semiColon]()); -:1096: assert(toks[5].text() == "// comment 1"); -:1097: assert(toks[5].type == TokenType.lineComment); -:1098: assert(toks[6].text() == "virtual"); -:1099: assert(toks[6].isTok:[id]()); -:1100: assert(toks[7].text() == "unit"); -:1101: assert(toks[7].isTok:[$unit]()); -:1102: assert(toks[8].text() == "c"); -:1103: assert(toks[9].text() == ";"); -:1104: assert(toks[10].text() == "// comment 2"); -:1105: assert(toks[11].text() == "virtual"); -:1106: assert(toks[12].text() == "unit"); -:1107: assert(toks[13].text() == "d"); -:1108: assert(toks[14].text() == ";"); -:1109: assert(toks[15].text() == "// comment 3"); -:1110: assert(toks[16].text() == "// comment 4"); -:1111: assert(toks[17].text() == ";"); -:1112: assert(toks[18].text() == ";"); -:1113: assert(toks[19].text() == ";"); -:1114: assert(toks[20].text() == "..."); -:1115: assert(toks[20].type == ellipsis); -:1116: assert(toks[21].text() == ".."); -:1117: delete lx; -:1118:} -:1119: -:1120:/// Tests the symbols and single char operators. -:1121:@unittest function test2() -:1122:{ -:1123: const s32 line = (echo(line) + 2):s32; -:1124: const s8[] source = `.:;,()/[]{}*+-!@=<>&$^%?~`; -:1125: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1126: var Token*[+] toks = lx.array(); -:1127: assert(toks.length == source.length + 1); -:1128: foreach (const u64 i; const Token* tk) in toks do -:1129: if i != toks.length - 1 do -:1130: assert(toks[i].text() == source[i..i+1]); -:1131: delete lx; -:1132:} -:1133: -:1134:/// Null chars are allowed between two tokens -:1135:@unittest function test3() -:1136:{ -:1137: const s32 line = (echo(line) + 2):s32; -:1138: const s8[] source = "1a\x00b"; -:1139: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1140: var Token*[+] toks = lx.array(); -:1141: assert(toks.length == 3); -:1142: assert(toks[0].text() == "1a"); -:1143: assert(toks[1].isTok:[id]()); -:1144: assert(toks[1].text() == "b"); -:1145: delete lx; -:1146:} -:1147: -:1148:@unittest function test4() -:1149:{ -:1150: const s32 line = (echo(line) + 1):s32; -:1151: const s8[] source = "a"; -:1152: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1153: var Token*[+] toks = lx.array(); -:1154: assert(toks.length == 2); -:1155: assert(toks[0].isTok:[id]()); -:1156: assert(toks[1].type == TokenType.eof); -:1157: delete lx; -:1158:} -:1159: -:1160:@unittest function test5() -:1161:{ -:1162: const s32 line = (echo(line) + 1):s32; -:1163: const s8[] source = `A0m`; -:1164: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1165: var Token*[+] toks = lx.array(); -:1166: assert(toks.length == 2); -:1167: assert(toks[0].text() == source); -:1168: delete lx; -:1169:} -:1170: -:1171:@unittest function test6() -:1172:{ -:1173: const s32 line = (echo(line) + 1):s32; -:1174: const s8[] source = `/`; -:1175: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1176: var Token*[+] toks = lx.array(); -:1177: assert(toks.length == 2); -:1178: assert(toks[0].text() == source); -:1179: delete lx; -:1180:} -:1181: -:1182:@unittest function test7() -:1183:{ -:1184: const s32 line = (echo(line) + 1):s32; -:1185: const s8[] source = `" -:1186: multiple lines -:1187: "`; -:1188: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1189: var Token*[+] toks = lx.array(); -:1190: assert(toks.length == 2); -:1191: assert(toks[0].type == stringLiteral); -:1192: delete lx; -:1193:} -:1194: -:1195:@unittest function test8() -:1196:{ -:1197: const s32 line = (echo(line) + 1):s32; -:1198: const s8[] source = "s8\r\ns16"; -:1199: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1200: var Token*[+] toks = lx.array(); -:1201: assert(toks.length == 3); -:1202: assert(toks[0].type == TokenType.$s8); -:1203: assert(toks[1].type == TokenType.$s16); -:1204: assert(toks[1].line() == toks[0].line() + 1); -:1205: delete lx; -:1206:} -:1207: -:1208:@unittest function test9() -:1209:{ -:1210: const s32 line = (echo(line) + 1):s32; -:1211: const s8[] source = `//`; -:1212: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1213: var Token*[+] toks = lx.array(); -:1214: assert(toks.length == 2); -:1215: assert(toks[0].text() == source); -:1216: delete lx; -:1217:} -:1218: -:1219:@unittest function test10() -:1220:{ -:1221: const s32 line = (echo(line) + 1):s32; -:1222: const s8[] source = `//3456789012`; -:1223: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1224: var Token*[+] toks = lx.array(); -:1225: assert(toks.length == 2); -:1226: assert(toks[0].text() == source); -:1227: delete lx; -:1228:} -:1229: -:1230:@unittest function test11() -:1231:{ -:1232: const s32 line = (echo(line) + 1):s32; -:1233: const s8[] source = `// -:1234: /* -:1235: */ -:1236: // -:1237: /**/`; -:1238: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1239: var Token*[+] toks = lx.array(); -:1240: assert(toks.length == 5); -:1241: assert(toks[0].type == lineComment); -:1242: assert(toks[1].type == starComment); -:1243: assert(toks[2].type == lineComment); -:1244: assert(toks[3].type == starComment); -:1245: delete lx; -:1246:} -:1247: -:1248:@unittest function test12() -:1249:{ -:1250: const s32 line = (echo(line) + 1):s32; -:1251: const s8[] source = `/*`; -:1252: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1253: var Token*[+] toks = lx.array(); -:1254: assert(toks.length == 2); -:1255: assert(toks[0].type == invalid); -:1256: delete lx; -:1257:} -:1258: -:1259:@unittest function test13() -:1260:{ -:1261: const s32 line = (echo(line) + 1):s32; -:1262: const s8[] source = "\xFF"; -:1263: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1264: var Token*[+] toks = lx.array(); -:1265: assert(toks.length == 1); -:1266: assert(toks[0].type == TokenType.eof); -:1267: delete lx; -:1268:} -:1269: -:1270:@unittest function test14() -:1271:{ -:1272: const s32 line = (echo(line) + 1):s32; -:1273: const s8[] source = "/*nullchar\x00"; -:1274: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1275: var Token*[+] toks = lx.array(); -:1276: assert(toks.length == 2); -:1277: assert(toks[0].type == invalid); -:1278: delete lx; -:1279:} -:1280: -:1281:@unittest function test15() -:1282:{ -:1283: const s32 line = (echo(line) + 1):s32; -:1284: const s8[] source = `a`; -:1285: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1286: var Token*[+] toks = lx.array(); -:1287: assert(toks.length == 2); -:1288: assert(toks[0].text() == source); -:1289: delete lx; -:1290:} -:1291: -:1292:@unittest function test16() -:1293:{ -:1294: const s32 line = (echo(line) + 1):s32; -:1295: const s8[] source = `12345678`; -:1296: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1297: var Token*[+] toks = lx.array(); -:1298: assert(toks.length == 2); -:1299: assert(toks[0].text() == source); -:1300: assert(toks[0].type == intLiteral); -:1301: delete lx; -:1302:} -:1303: -:1304:@unittest function test17() -:1305:{ -:1306: const s32 line = (echo(line) + 1):s32; -:1307: const s8[] source = `1234.a`; -:1308: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1309: var Token*[+] toks = lx.array(); -:1310: assert(toks.length == 4); -:1311: assert(toks[0].type == intLiteral); -:1312: assert(toks[0].text() == "1234"); -:1313: assert(toks[1].isTok:[dot]()); -:1314: assert(toks[2].isTok:[id]()); -:1315: assert(toks[2].text() == "a"); -:1316: delete lx; -:1317:} -:1318: -:1319:@unittest function test18() -:1320:{ -:1321: const s32 line = (echo(line) + 1):s32; -:1322: const s8[] source = `(0)`; -:1323: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1324: var Token*[+] toks = lx.array(); -:1325: assert(toks.length == 4); -:1326: assert(toks[0].type == leftParen); -:1327: assert(toks[1].type == intLiteral); -:1328: assert(toks[2].type == rightParen); -:1329: delete lx; -:1330:} -:1331: -:1332:@unittest function test19() -:1333:{ -:1334: const s32 line = (echo(line) + 1):s32; -:1335: const s8[] source = `1234.01`; -:1336: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1337: var Token*[+] toks = lx.array(); -:1338: assert(toks.length == 2); -:1339: assert(toks[0].type == floatLiteral); -:1340: assert(toks[0].text() == "1234.01"); -:1341: delete lx; -:1342:} -:1343: -:1344:@unittest function test20() -:1345:{ -:1346: const s32 line = (echo(line) + 1):s32; -:1347: const s8[] source = `-1234.01`; -:1348: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1349: var Token*[+] toks = lx.array(); -:1350: assert(toks.length == 3); -:1351: assert(toks[0].type == minus); -:1352: assert(toks[1].type == floatLiteral); -:1353: assert(toks[1].text() == source[1..source.length]); -:1354: delete lx; -:1355:} -:1356: -:1357:@unittest function test21() -:1358:{ -:1359: const s32 line = (echo(line) + 1):s32; -:1360: const s8[] source = `0x12AF20`; -:1361: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1362: var Token*[+] toks = lx.array(); -:1363: assert(toks.length == 2); -:1364: assert(toks[0].type == hexLiteral); -:1365: assert(toks[0].text() == source); -:1366: delete lx; -:1367:} -:1368: -:1369:@unittest function test22() -:1370:{ -:1371: const s32 line = (echo(line) + 1):s32; -:1372: const s8[] source = `0X1234_abcdef`; -:1373: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1374: var Token*[+] toks = lx.array(); -:1375: assert(toks.length == 2); -:1376: assert(toks[0].type == hexLiteral); -:1377: assert(toks[0].text() == source); -:1378: delete lx; -:1379:} -:1380: -:1381:@unittest function test23() -:1382:{ -:1383: const s32 line = (echo(line) + 1):s32; -:1384: const s8[] source = `s8 /*s16*/ s32`; -:1385: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1386: var Token*[+] toks = lx.array(); -:1387: assert(toks.length == 4); -:1388: assert(toks[0].type == TokenType.$s8); -:1389: assert(toks[1].type == TokenType.starComment); -:1390: assert(toks[1].text() == "/*s16*/"); -:1391: assert(toks[2].type == TokenType.$s32); -:1392: delete lx; -:1393:} -:1394: -:1395:@unittest function test24() -:1396:{ -:1397: const s32 line = (echo(line) + 1):s32; -:1398: const s8[] source = "s8 /*\n/*\n*/ s32"; -:1399: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1400: var Token*[+] toks = lx.array(); -:1401: assert(toks.length == 4); -:1402: assert(toks[0].type == TokenType.$s8); -:1403: assert(toks[1].type == TokenType.starComment); -:1404: assert(toks[1].text() == "/*\n/*\n*/"); -:1405: assert(toks[2].type == TokenType.$s32); -:1406: delete lx; -:1407:} -:1408: -:1409:@unittest function test25() -:1410:{ -:1411: const s32 line = (echo(line) + 1):s32; -:1412: const s8[] source = `8 >= 1 <= 0`; -:1413: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1414: var Token*[+] toks = lx.array(); -:1415: assert(toks.length == 6); -:1416: assert(toks[0].type == intLiteral); -:1417: assert(toks[1].type == greaterEqual); -:1418: assert(toks[2].type == intLiteral); -:1419: assert(toks[3].type == lesserEqual); -:1420: assert(toks[4].type == intLiteral); -:1421: delete lx; -:1422:} -:1423: -:1424:@unittest function test26() -:1425:{ -:1426: const s32 line = (echo(line) + 1):s32; -:1427: const s8[] source = `+++`; -:1428: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1429: var Token*[+] toks = lx.array(); -:1430: assert(toks.length == 3); -:1431: assert(toks[0].type == plusPlus); -:1432: assert(toks[1].type == plus); -:1433: delete lx; -:1434:} -:1435: -:1436:@unittest function test27() -:1437:{ -:1438: const s32 line = (echo(line) + 1):s32; -:1439: const s8[] source = `---`; -:1440: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1441: var Token*[+] toks = lx.array(); -:1442: assert(toks.length == 3); -:1443: assert(toks[0].type == minMin); -:1444: assert(toks[1].type == minus); -:1445: delete lx; -:1446:} -:1447: -:1448:@unittest function test28() -:1449:{ -:1450: const s32 line = (echo(line) + 1):s32; -:1451: const s8[] source = `+ "abcdef" -`; -:1452: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1453: var Token*[+] toks = lx.array(); -:1454: assert(toks.length == 4); -:1455: assert(toks[0].type == plus); -:1456: assert(toks[1].type == stringLiteral); -:1457: assert(toks[1].text() == "abcdef"); -:1458: assert(toks[2].type == minus); -:1459: delete lx; -:1460:} -:1461: -:1462:@unittest function test29() -:1463:{ -:1464: const s32 line = (echo(line) + 1):s32; -:1465: const s8[] source = `s64 alias a`; -:1466: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1467: var Token*[+] toks = lx.array(); -:1468: assert(toks.length == 4); -:1469: assert(toks[0].isTokBasicType()); -:1470: assert(toks[1].type == $alias); -:1471: assert(toks[2].type == id); -:1472: delete lx; -:1473:} -:1474: -:1475:@unittest function test30() -:1476:{ -:1477: const s32 line = (echo(line) + 1):s32; -:1478: const s8[] source = `$function $identifier`; -:1479: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1480: var Token*[+] toks = lx.array(); -:1481: assert(toks.length == 3); -:1482: assert(toks[0].isTok:[id]()); -:1483: assert(toks[0].keywordAsIdentifier()); -:1484: assert(toks[0].text() == "function"); -:1485: assert(toks[1].isTok:[id]()); -:1486: assert(toks[1].text() == "identifier"); -:1487: delete lx; -:1488:} -:1489: -:1490:@unittest function test31() -:1491:{ -:1492: const s32 line = (echo(line) + 1):s32; -:1493: const s8[] source = `==|`; -:1494: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1495: var Token*[+] toks = lx.array(); -:1496: assert(toks.length == 3); -:1497: assert(toks[0].type == equal); -:1498: assert(toks[1].type == TokenType.pipe); -:1499: delete lx; -:1500:} -:1501: -:1502:@unittest function test32() -:1503:{ -:1504: const s32 line = (echo(line) + 1):s32; -:1505: const s8[] source = `&&&`; -:1506: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1507: var Token*[+] toks = lx.array(); -:1508: assert(toks.length == 3); -:1509: assert(toks[0].type == andAnd); -:1510: assert(toks[1].type == amp); -:1511: delete lx; -:1512:} -:1513: -:1514:@unittest function test33() -:1515:{ -:1516: const s32 line = (echo(line) + 1):s32; -:1517: const s8[] source = `|||`; -:1518: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1519: var Token*[+] toks = lx.array(); -:1520: assert(toks.length == 3); -:1521: assert(toks[0].type == orOr); -:1522: assert(toks[1].type == TokenType.pipe); -:1523: delete lx; -:1524:} -:1525: -:1526:@unittest function test34() -:1527:{ -:1528: const s32 line = (echo(line) + 1):s32; -:1529: const s8[] source = `>>>`; -:1530: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1531: var Token*[+] toks = lx.array(); -:1532: assert(toks.length == 3); -:1533: assert(toks[0].type == rShift); -:1534: assert(toks[1].type == greater); -:1535: delete lx; -:1536:} -:1537: -:1538:@unittest function test35() -:1539:{ -:1540: const s32 line = (echo(line) + 1):s32; -:1541: const s8[] source = `<<<`; -:1542: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1543: var Token*[+] toks = lx.array(); -:1544: assert(toks.length == 3); -:1545: assert(toks[0].type == lShift); -:1546: assert(toks[1].type == lesser); -:1547: delete lx; -:1548:} -:1549: -:1550:@unittest function test36() -:1551:{ -:1552: const s32 line = (echo(line) + 1):s32; -:1553: const s8[] source = `!!=`; -:1554: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1555: var Token*[+] toks = lx.array(); -:1556: assert(toks.length == 3); -:1557: assert(toks[0].type == not); -:1558: assert(toks[1].type == notEqual); -:1559: delete lx; -:1560:} -:1561: -:1562:@unittest function test37() -:1563:{ -:1564: const s32 line = (echo(line) + 1):s32; -:1565: const s8[] source = "aa\x00"; -:1566: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1567: var Token*[+] toks = lx.array(); -:1568: assert(toks.length == 2); -:1569: assert(toks[0].type == invalid); -:1570: delete lx; -:1571:} -:1572: -:1573:@unittest function test38() -:1574:{ -:1575: const s32 line = (echo(line) + 1):s32; -:1576: const s8[] source = "/*\x00"; -:1577: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1578: var Token*[+] toks = lx.array(); -:1579: assert(toks.length == 2); -:1580: assert(toks[0].type == invalid); -:1581: delete lx; -:1582:} -:1583: -:1584:@unittest function test39() -:1585:{ -:1586: const s32 line = (echo(line) + 1):s32; -:1587: const s8[] source = "//\x00"; -:1588: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1589: var Token*[+] toks = lx.array(); -:1590: assert(toks.length == 2); -:1591: assert(toks[0].type == invalid); -:1592: delete lx; -:1593:} -:1594: -:1595:@unittest function test40() -:1596:{ -:1597: const s32 line = (echo(line) + 1):s32; -:1598: const s8[] source = "0\x00"; -:1599: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1600: var Token*[+] toks = lx.array(); -:1601: assert(toks.length == 2); -:1602: assert(toks[0].type == invalid); -:1603: delete lx; -:1604:} -:1605: -:1606:@unittest function test41() -:1607:{ -:1608: const s32 line = (echo(line) + 1):s32; -:1609: const s8[] source = "0.0\x00"; -:1610: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1611: var Token*[+] toks = lx.array(); -:1612: assert(toks.length == 2); -:1613: assert(toks[0].type == invalid); -:1614: delete lx; -:1615:} -:1616: -:1617:@unittest function test42() -:1618:{ -:1619: const s32 line = (echo(line) + 1):s32; -:1620: const s8[] source = "0x1\x00"; -:1621: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1622: var Token*[+] toks = lx.array(); -:1623: assert(toks.length == 2); -:1624: assert(toks[0].type == hexLiteral); -:1625: assert(toks[1].type == TokenType.eof); -:1626: delete lx; -:1627:} -:1628: -:1629:@unittest function test43() -:1630:{ -:1631: const s32 line = (echo(line) + 1):s32; -:1632: const s8[] source = "\"stringliteral\x00"; -:1633: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1634: var Token*[+] toks = lx.array(); -:1635: assert(toks.length == 2); -:1636: assert(toks[0].type == invalid); -:1637: delete lx; -:1638:} -:1639: -:1640:@unittest function test44() -:1641:{ -:1642: const s32 line = (echo(line) + 1):s32; -:1643: const s8[] source = "0x1Y"; -:1644: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1645: var Token*[+] toks = lx.array(); -:1646: assert(toks.length == 2); -:1647: assert(toks[0].type == invalid); -:1648: delete lx; -:1649:} -:1650: -:1651:@unittest function test45() -:1652:{ -:1653: const s32 line = (echo(line) + 1):s32; -:1654: const s8[] source = "0x1z"; -:1655: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1656: var Token*[+] toks = lx.array(); -:1657: assert(toks.length == 2); -:1658: assert(toks[0].type == invalid); -:1659: delete lx; -:1660:} -:1661: -:1662:@unittest function test46() -:1663:{ -:1664: const s32 line = (echo(line) + 1):s32; -:1665: const s8[] source = "0/0"; -:1666: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1667: var Token*[+] toks = lx.array(); -:1668: assert(toks.length == 4); -:1669: assert(toks[0].type == intLiteral); -:1670: assert(toks[1].type == div); -:1671: assert(toks[2].type == intLiteral); -:1672: assert(toks[3].type == TokenType.eof); -:1673: delete lx; -:1674:} -:1675: -:1676:@unittest function test47() -:1677:{ -:1678: const s32 line = (echo(line) + 1):s32; -:1679: const s8[] source = "1_000.000_000"; -:1680: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1681: var Token*[+] toks = lx.array(); -:1682: assert(toks.length == 2); -:1683: assert(toks[0].type == floatLiteral); -:1684: assert(toks[1].type == TokenType.eof); -:1685: delete lx; -:1686:} -:1687: -:1688:@unittest function test48() -:1689:{ -:1690: const u32 line = (echo(line) + 1):u32; -:1691: const s8[] source = "#!bin/styx -until=parsing \r\n unit a;"; -:1692: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1693: var Token*[+] toks = lx.array(); -:1694: assert(toks.length == 4); -:1695: assert(toks[0].type == $unit); -:1696: assert(toks[0].line() == line + 1); -:1697: delete lx; -:1698:} -:1699: -:1700:@unittest function test49() -:1701:{ -:1702: const s32 line = (echo(line) + 1):s32; -:1703: const s8[] source = "#!"; -:1704: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1705: var Token*[+] toks = lx.array(); -:1706: assert(toks.length == 1); -:1707: assert(toks[0].type == TokenType.eof); -:1708: delete lx; -:1709:} -:1710: -:1711:@unittest function test50() -:1712:{ -:1713: const s32 line = (echo(line) + 1):s32; -:1714: const s8[] source = `"unterminated`; -:1715: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1716: var Token*[+] toks = lx.array(); -:1717: assert(toks.length == 2); -:1718: assert(toks[0].type == invalid); -:1719: delete lx; -:1720:} -:1721: -:1722:@unittest function test51() -:1723:{ -:1724: const s32 line = (echo(line) + 1):s32; -:1725: const s8[] source = `"unterminated\"`; -:1726: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1727: var Token*[+] toks = lx.array(); -:1728: assert(toks.length == 2); -:1729: assert(toks[0].type == invalid); -:1730: delete lx; -:1731:} -:1732: -:1733:@unittest function test52() -:1734:{ -:1735: const s32 line = (echo(line) + 1):s32; -:1736: const s8[] source = `"terminated_by_double_quote\""`; -:1737: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1738: var Token*[+] toks = lx.array(); -:1739: assert(toks.length == 2); -:1740: assert(toks[0].type == stringLiteral); -:1741: assert(stringRepresentation(toks[0]) == source[1..source.length-1]); -:1742: delete lx; -:1743:} -:1744: -:1745:@unittest function test53() -:1746:{ -:1747: const s32 line = (echo(line) + 1):s32; -:1748: const s8[] source = "`rawString`"; -:1749: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1750: var Token*[+] toks = lx.array(); -:1751: assert(toks.length == 2); -:1752: assert(toks[0].type == rawStringLiteral); -:1753: assert(toks[0].text() == source[1..source.length-1]); -:1754: delete lx; -:1755:} -:1756: -:1757:@unittest function test54() -:1758:{ -:1759: const s32 line = (echo(line) + 1):s32; -:1760: const s8[] source = "`rawString"; -:1761: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1762: var Token*[+] toks = lx.array(); -:1763: assert(toks.length == 2); -:1764: assert(toks[0].type == invalid); -:1765: delete lx; -:1766:} -:1767: -:1768:@unittest function test55() -:1769:{ -:1770: const s32 line = (echo(line) + 1):s32; -:1771: const s8[] source = "00000"; -:1772: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1773: var Token*[+] toks = lx.array(); -:1774: assert(toks.length == 2); -:1775: assert(toks[0].type == intLiteral); -:1776: delete lx; -:1777:} -:1778: -:1779:@unittest function test56() -:1780:{ -:1781: const s32 line = (echo(line) + 1):s32; -:1782: const s8[] source = "0x0AAAA"; -:1783: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1784: var Token*[+] toks = lx.array(); -:1785: assert(toks.length == 2); -:1786: assert(toks[0].type == hexLiteral); -:1787: delete lx; -:1788:} -:1789: -:1790:@unittest function test57() -:1791:{ -:1792: const s32 line = (echo(line) + 1):s32; -:1793: const s8[] source = "0.01"; -:1794: var Lexer* lx = (new Lexer).createFromText(source[0..3], echo(filename), line, 20, false); -:1795: var Token*[+] toks = lx.array(); -:1796: assert(toks.length == 2); -:1797: assert(toks[0].type == floatLiteral); -:1798: assert(toks[0].text() == "0.0"); -:1799: delete lx; -:1800:} -:1801: -:1802:@unittest function test58() -:1803:{ -:1804: const s32 line = (echo(line) + 1):s32; -:1805: const s8[] source = "`rawString\x00"; -:1806: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1807: var Token*[+] toks = lx.array(); -:1808: assert(toks.length == 2); -:1809: assert(toks[0].type == invalid); -:1810: delete lx; -:1811:} -:1812: -:1813:@unittest function test59() -:1814:{ -:1815: const s32 line = (echo(line) + 1):s32; -:1816: const s8[] source = `a+=`; -:1817: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1818: var Token*[+] toks = lx.array(); -:1819: assert(toks.length == 3); -:1820: assert(toks[0].type == id); -:1821: assert(toks[1].type == plusAss); -:1822: delete lx; -:1823:} -:1824: -:1825:@unittest function test60() -:1826:{ -:1827: const s32 line = (echo(line) + 1):s32; -:1828: const s8[] source = `a-=`; -:1829: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1830: var Token*[+] toks = lx.array(); -:1831: assert(toks.length == 3); -:1832: assert(toks[0].type == id); -:1833: assert(toks[1].type == minusAss); -:1834: delete lx; -:1835:} -:1836: -:1837:@unittest function test61() -:1838:{ -:1839: const s32 line = (echo(line) + 1):s32; -:1840: const s8[] source = `a*=`; -:1841: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1842: var Token*[+] toks = lx.array(); -:1843: assert(toks.length == 3); -:1844: assert(toks[0].type == id); -:1845: assert(toks[1].type == mulAss); -:1846: delete lx; -:1847:} -:1848: -:1849:@unittest function test62() -:1850:{ -:1851: const s32 line = (echo(line) + 1):s32; -:1852: const s8[] source = `a/=`; -:1853: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1854: var Token*[+] toks = lx.array(); -:1855: assert(toks.length == 3); -:1856: assert(toks[0].type == id); -:1857: assert(toks[1].type == divAss); -:1858: delete lx; -:1859:} -:1860: -:1861:@unittest function test63() -:1862:{ -:1863: const s32 line = (echo(line) + 1):s32; -:1864: const s8[] source = `a%=`; -:1865: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1866: var Token*[+] toks = lx.array(); -:1867: assert(toks.length == 3); -:1868: assert(toks[0].type == id); -:1869: assert(toks[1].type == modAss); -:1870: delete lx; -:1871:} -:1872: -:1873:@unittest function test64() -:1874:{ -:1875: const s32 line = (echo(line) + 1):s32; -:1876: const s8[] source = `a&=`; -:1877: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1878: var Token*[+] toks = lx.array(); -:1879: assert(toks.length == 3); -:1880: assert(toks[0].type == id); -:1881: assert(toks[1].type == ampAss); -:1882: delete lx; -:1883:} -:1884: -:1885:@unittest function test65() -:1886:{ -:1887: const s32 line = (echo(line) + 1):s32; -:1888: const s8[] source = `a|=`; -:1889: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1890: var Token*[+] toks = lx.array(); -:1891: assert(toks.length == 3); -:1892: assert(toks[0].type == id); -:1893: assert(toks[1].type == pipeAss); -:1894: delete lx; -:1895:} -:1896: -:1897:@unittest function test66() -:1898:{ -:1899: const s32 line = (echo(line) + 1):s32; -:1900: const s8[] source = `a^=`; -:1901: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1902: var Token*[+] toks = lx.array(); -:1903: assert(toks.length == 3); -:1904: assert(toks[0].type == id); -:1905: assert(toks[1].type == xorAss); -:1906: delete lx; -:1907:} -:1908: -:1909:@unittest function test67() -:1910:{ -:1911: const s32 line = (echo(line) + 1):s32; -:1912: const s8[] source = `a<<=`; -:1913: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1914: var Token*[+] toks = lx.array(); -:1915: assert(toks.length == 3); -:1916: assert(toks[0].type == id); -:1917: assert(toks[1].type == lshiftAss); -:1918: delete lx; -:1919:} -:1920: -:1921:@unittest function test68() -:1922:{ -:1923: const s32 line = (echo(line) + 1):s32; -:1924: const s8[] source = `a>>=`; -:1925: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1926: var Token*[+] toks = lx.array(); -:1927: assert(toks.length == 3); -:1928: assert(toks[0].type == id); -:1929: assert(toks[1].type == rshiftAss); -:1930: delete lx; -:1931:} -:1932: -:1933:@unittest function test69() -:1934:{ -:1935: const s32 line = (echo(line) + 1):s32; -:1936: const s8[] source = `a?..`; -:1937: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1938: var Token*[+] toks = lx.array(); -:1939: assert(toks.length == 4); -:1940: assert(toks[0].type == id); -:1941: assert(toks[1].type == qmark); -:1942: assert(toks[2].type == dotDot); -:1943: delete lx; -:1944:} -:1945: -:1946:@unittest function test70() -:1947:{ -:1948: const s32 line = (echo(line) + 1):s32; -:1949: const s8[] source = "\xEF\xBB\xBF"; -:1950: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1951: var Token*[+] toks = lx.array(); -:1952: assert(toks.length == 1); -:1953: assert(toks[0].type == TokenType.eof); -:1954: delete lx; -:1955:} -:1956: -:1957:@unittest function test71() -:1958:{ -:1959: const s32 line = (echo(line) + 1):s32; -:1960: const s8[] source = "\xEF\xBB\xBFunit a;"; -:1961: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1962: var Token*[+] toks = lx.array(); -:1963: assert(toks.length == 4); -:1964: assert(toks[0].isTok:[$unit]() && toks[0].column() == 1); -:1965: assert(toks[1].isTok:[id]()); -:1966: assert(toks[2].isTok:[semiColon]()); -:1967: assert(toks[3].type == TokenType.eof); -:1968: delete lx; -:1969:} -:1970: -:1971:@unittest function test72() -:1972:{ -:1973: const s32 line = (echo(line) + 1):s32; -:1974: const s8[] source = "\xEF\xBB\xBB"; -:1975: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1976: var Token*[+] toks = lx.array(); -:1977: assert(toks.length == 1); -:1978: assert(toks[0].type == TokenType.eof); -:1979: delete lx; -:1980:} -:1981: -:1982:@unittest function test73() -:1983:{ -:1984: const s32 line = (echo(line) + 1):s32; -:1985: const s8[] source = "unit \\"; -:1986: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:1987: var Token*[+] toks = lx.array(); -:1988: assert(toks.length == 3); -:1989: assert(toks[0].isTok:[$unit]()); -:1990: assert(toks[1].type == TokenType.invalid); -:1991: assert(toks[2].type == TokenType.eof); -:1992: delete lx; -:1993:} -:1994: -:1995:@unittest function test74() -:1996:{ -:1997: const s32 line = (echo(line) + 1):s32; -:1998: const s8[] source = "^~...? null true false % assert"; -:1999: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2000: var Token*[+] toks = lx.array(); -:2001: assert(toks.length == 10); -:2002: assert(toks[0].type == TokenType.xor); -:2003: assert(toks[1].type == TokenType.tidle); -:2004: assert(toks[2].type == TokenType.ellipsis); -:2005: assert(toks[3].type == TokenType.qmark); -:2006: assert(toks[4].type == TokenType.$null); -:2007: assert(toks[5].type == TokenType.$true); -:2008: assert(toks[7].type == TokenType.mod); -:2009: assert(toks[8].type == TokenType.$assert); -:2010: assert(toks[9].type == TokenType.eof); -:2011: delete lx; -:2012:} -:2013: -:2014:@unittest function test75() -:2015:{ -:2016: const s32 line = (echo(line) + 1):s32; -:2017: const s8[] source = `0.1E1 0.1e+1 123.1e-1`; -:2018: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2019: var Token*[+] toks = lx.array(); -:2020: assert(toks.length == 4); -:2021: assert(toks[0].type == TokenType.floatLiteral); -:2022: assert(toks[1].type == TokenType.floatLiteral); -:2023: assert(toks[2].type == TokenType.floatLiteral); -:2024: delete lx; -:2025:} -:2026: -:2027:@unittest function test76() -:2028:{ -:2029: const s32 line = (echo(line) + 1):s32; -:2030: const s8[] source = "0.1E\x00"; -:2031: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2032: var Token*[+] toks = lx.array(); -:2033: assert(toks.length == 2); -:2034: assert(toks[0].type == TokenType.invalid); -:2035: delete lx; -:2036:} -:2037: -:2038:@unittest function test77() -:2039:{ -:2040: const s32 line = (echo(line) + 1):s32; -:2041: const s8[] source = "0bR"; -:2042: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2043: var Token*[+] toks = lx.array(); -:2044: assert(toks.length == 2); -:2045: assert(toks[0].type == TokenType.invalid); -:2046: assert(toks[1].type == TokenType.eof); -:2047: delete lx; -:2048:} -:2049: -:2050:@unittest function test78() -:2051:{ -:2052: const s32 line = (echo(line) + 1):s32; -:2053: const s8[] source = "0xR 0x00_1"; -:2054: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2055: var Token*[+] toks = lx.array(); -:2056: assert(toks.length == 3); -:2057: assert(toks[0].type == TokenType.invalid); -:2058: assert(toks[0].text() == "0xR"); -:2059: assert(toks[1].type == TokenType.hexLiteral); -:2060: assert(toks[2].type == TokenType.eof); -:2061: delete lx; -:2062:} -:2063: -:2064:@unittest function test79() -:2065:{ -:2066: const s32 line = (echo(line) + 1):s32; -:2067: const s8[] source = "0b"; -:2068: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2069: var Token*[+] toks = lx.array(); -:2070: assert(toks.length == 2); -:2071: assert(toks[0].type == TokenType.invalid); -:2072: assert(toks[1].type == TokenType.eof); -:2073: delete lx; -:2074:} -:2075: -:2076:@unittest function test80() -:2077:{ -:2078: const s32 line = (echo(line) + 1):s32; -:2079: const s8[] source = "0x"; -:2080: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2081: var Token*[+] toks = lx.array(); -:2082: assert(toks.length == 2); -:2083: assert(toks[0].type == TokenType.invalid); -:2084: assert(toks[1].type == TokenType.eof); -:2085: delete lx; -:2086:} -:2087: -:2088:@unittest function test81() -:2089:{ -:2090: const s32 line = (echo(line) + 1):s32; -:2091: const s8[] source = "0b11_00_11 true 0b11_00_11"; -:2092: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2093: var Token*[+] toks = lx.array(); -:2094: assert(toks.length == 4); -:2095: assert(toks[0].type == TokenType.binLiteral); -:2096: assert(toks[1].type == TokenType.$true); -:2097: assert(toks[3].type == TokenType.eof); -:2098: delete lx; -:2099:} -:2100: -:2101:@unittest function test82() -:2102:{ -:2103: const s32 line = (echo(line) + 1):s32; -:2104: const s8[] source = "class struct union null"; -:2105: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2106: var Token*[+] toks = lx.array(); -:2107: assert(toks.length == 5); -:2108: assert(toks[0].type == TokenType.$class); -:2109: assert(toks[1].type == TokenType.$struct); -:2110: assert(toks[2].type == TokenType.$union); -:2111: assert(toks[3].type == TokenType.$null); -:2112: assert(toks[4].type == TokenType.eof); -:2113: delete lx; -:2114:} -:2115: -:2116:@unittest function test83() -:2117:{ -:2118: const s32 line = (echo(line) + 1):s32; -:2119: const s8[] source = `"\"ab\r\n\r\n"`; -:2120: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2121: var Token*[+] toks = lx.array(); -:2122: assert(toks.length == 2); -:2123: assert(toks[0].type == stringLiteral); -:2124: assert(stringRepresentation(toks[0]) == `\"ab\x0D\x0A\x0D\x0A`); -:2125: assert(toks[1].type == TokenType.eof); -:2126: delete lx; -:2127:} -:2128: -:2129:@unittest function test83_2() -:2130:{ -:2131: const s32 line = (echo(line) + 1):s32; -:2132: const s8[] source = `"\"ab\x0d\x0a\x0D\x0A \x51"`; -:2133: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2134: var Token*[+] toks = lx.array(); -:2135: assert(toks.length == 2); -:2136: assert(toks[0].type == stringLiteral); -:2137: assert(stringRepresentation(toks[0]) == `\"ab\x0D\x0A\x0D\x0A Q`); -:2138: assert(toks[1].type == TokenType.eof); -:2139: delete lx; -:2140:} -:2141: -:2142:@unittest function test84() -:2143:{ -:2144: const s32 line = (echo(line) + 1):s32; -:2145: const s8[] source = `"\r\n\0bad_scape\S"`; -:2146: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2147: var Token*[+] toks = lx.array(); -:2148: assert(toks.length == 4); -:2149: assert(toks[0].type == TokenType.invalid); // \r\n\0bad_scape\ -:2150: assert(toks[1].type == TokenType.id); // S -:2151: assert(toks[2].type == TokenType.invalid); // " -:2152: assert(toks[3].type == TokenType.eof); -:2153: delete lx; -:2154:} -:2155: -:2156:@unittest function test85() -:2157:{ -:2158: const s32 line = (echo(line) + 1):s32; -:2159: const s8[] source = `"bad_scape\xH"`; -:2160: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2161: var Token*[+] toks = lx.array(); -:2162: assert(toks.length == 4); -:2163: assert(toks[0].type == TokenType.invalid); // bad_scape\x -:2164: assert(toks[1].type == TokenType.id); // H -:2165: assert(toks[2].type == TokenType.invalid); // " -:2166: assert(toks[3].type == TokenType.eof); -:2167: delete lx; -:2168:} -:2169: -:2170:@unittest function test86() -:2171:{ -:2172: const s32 line = (echo(line) + 1):s32; -:2173: const s8[] source = `"bad_scape\`; -:2174: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2175: var Token*[+] toks = lx.array(); -:2176: assert(toks.length == 3); -:2177: assert(toks[0].type == TokenType.invalid); -:2178: assert(toks[1].type == TokenType.invalid); -:2179: assert(toks[2].type == TokenType.eof); -:2180: delete lx; -:2181:} -:2182: -:2183:@unittest function test87() -:2184:{ -:2185: const s32 line = (echo(line) + 1):s32; -:2186: const s8[] source = `"\\"`; -:2187: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2188: var Token*[+] toks = lx.array(); -:2189: assert(toks.length == 2); -:2190: assert(toks[0].type == stringLiteral); -:2191: assert(toks[0].text() == `\`); -:2192: assert(toks[1].type == TokenType.eof); -:2193: delete lx; -:2194:} -:2195: -:2196:@unittest function test88() -:2197:{ -:2198: const s32 line = (echo(line) + 1):s32; -:2199: const s8[] source = "\"}\n"; -:2200: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2201: var Token*[+] toks = lx.array(); -:2202: delete lx; -:2203:} -:2204: -:2205:@unittest function testBidi() -:2206:{ -:2207: const s32 line = (echo(line) + 1):s32; -:2208: { -:2209: const s8[] source = "\"\xE2\x80\x8A\""; -:2210: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2211: var Token*[+] toks = lx.array(); -:2212: delete lx; -:2213: } -:2214: { -:2215: const s8[] source = "\"\xE2\""; -:2216: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2217: var Token*[+] toks = lx.array(); -:2218: delete lx; -:2219: } -:2220: { -:2221: const s8[] source = "\"\xE2\x80\xAD\""; -:2222: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2223: var Token*[+] toks = lx.array(); -:2224: delete lx; -:2225: } -:2226: { -:2227: const s8[] source = "/*\xE2\x81\xA6*/"; -:2228: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), line, 20, false); -:2229: var Token*[+] toks = lx.array(); -:2230: delete lx; -:2231: } -:2232:} -:2233: -:2234:@unittest function test89() -:2235:{ -:2236: const s8[] source = "` -:2237: ... -:2238: ... -:2239: ...` -:2240: var\t\v\f"; -:2241: var Lexer* lx = (new Lexer).createFromText(source, echo(filename), 1, 20, false); -:2242: var Token*[+] toks = lx.array(); -:2243: assert(toks.length == 3); -:2244: assert(toks[1].position.line == 5); -:2245: delete lx; -:2246:} -:2247: -:2248:@unittest function coverMsgFunc() -:2249:{ -:2250: var Position p; -:2251: var auto old = session.messageFunc; -:2252: session.messageFunc = null; -:2253: session.warn("a.sx", p, "test"); -:2254: session.error("a.sx", p, "test"); -:2255: session.deprecation("a.sx", p, "test"); -:2256: session.messageFunc = old; -:2257:} <<<<<< EOF # path=src/styx/lint.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/lint.sx -: 1:unit styx.lint; -: 2: -: 3:@private import -: 4: styx.session, -: 5: styx.ast.base, -: 6: styx.ast.declarations, -: 7: styx.ast.expressions, -: 8: styx.ast.statements, -: 9: styx.ast.types, -: 10: styx.ast.visitor, -: 11: styx.ast.formatter, -: 12: styx.position, -: 13: styx.symbol, -: 14: styx.token, -: 15: ; -: 16: -: 17:/// Runs the linter modules included `lm` and if they only require the raw AST -: 18:function postLexicalPassLint(UnitDeclaration* u; LinterModules lm) -: 19:{ 12: 20: if assignInAssert in lm do -: 21: { -: 22: var AssignInAssertVisitor v; 1: 23: v.visitUnitDeclaration(u); -: 24: } 12: 25: if suggestBreakExp in lm do -: 26: { -: 27: var SuggestBreakExpVisitor v; 1: 28: v.visitUnitDeclaration(u); -: 29: } 12: 30:} -: 31: -: 32:/// Runs the linter modules included in `lm` and if they require the decorated AST -: 33:function postSemanticPassLint(UnitDeclaration* u; LinterModules lm) -: 34:{ 12: 35: if suggestOptAss in lm do -: 36: { -: 37: var SuggestOptionalAssignVisitor v; 1: 38: v.visitUnitDeclaration(u); -: 39: } 12: 40: if suggestCondExp in lm do -: 41: { -: 42: var SuggestCondExpVisitor v; 1: 43: v.visitUnitDeclaration(u); -: 44: } 12: 45: if suggestCondToLogical in lm do -: 46: { -: 47: var SuggestCondToLogical v; 1: 48: v.visitUnitDeclaration(u); -: 49: } 12: 50: if unusedImports in lm do -: 51: { -: 52: var UnusedImportsVisitor v; 12: 53: v.visitUnitDeclaration(u); -: 54: } 12: 55: if unusedLocals in lm do -: 56: { -: 57: var UnusedLocalsVisitor v; 1: 58: v.visitUnitDeclaration(u); -: 59: } 12: 60: if reslice in lm do -: 61: { -: 62: var ResliceVisitor v; 1: 63: v.visitUnitDeclaration(u); -: 64: } 12: 65: if loopInvariant in lm do -: 66: { -: 67: var LoopInvariantVisitor v; 1: 68: v.visitUnitDeclaration(u); -: 69: } 12: 70:} -: 71: -: 72:protection(private) -: 73: -: 74:class LintVisitor : AstVisitor -: 75:{ -: 76: var UnitDeclaration* $unit; -: 77: -: 78: @override function visitUnitDeclaration(UnitDeclaration* node) -: 79: { 8: 80: $unit = node; 8: 81: node.accept(this); 8: 82: } -: 83:} -: 84: -: 85:class PostSemaLintVisitor : LintVisitor -: 86:{ -: 87: // arguments are not always decorated, e.g `@operator(a+b)` -: 88: @override function visitAttribute(Attribute* node) -: 89: { 21: 90: foreach const auto arg in node.arguments do 21: 91: if arg.type do 7: 92: visitExpression(arg); 21: 93: } -: 94: -: 95: // the base generic delclaration is not decorated -: 96: @override function visitDeclaration(Declaration* node) -: 97: { 516: 98: if !node.genericParameters || node.genericParameters.applied() do 516: 99: visitConcreteDeclaration(node); 516:100: } -:101: -:102: @override function visitIfElseStatement(IfElseStatement* node) -:103: { 102:104: if node.ifVariable do 6:105: visitVariableDeclaration(node.ifVariable); 102:106: node.accept(this); 102:107: } -:108:} -:109: -:110:/* Warn if `if !e1 do e1 = e2` can rewritten `e1 ?= e2` -:111: -:112:1. the lexical pass is faster : less tokens to lex, less AST nodes. -:113:2. the backend produces better code because `e1` is only evaluated once. -:114:*/ -:115:@final class SuggestOptionalAssignVisitor : PostSemaLintVisitor -:116:{ -:117: @override function visitIfElseStatement(IfElseStatement* node) -:118: { 17:119: node.accept(this); 17:120: if !node.thenBlock || node.elseBlock do 1:121: return; -:122: -:123: var Expression* condition; 32:124: if var auto ce = node.condition:CmpExpression* do -:125: { 15:126: if ce.operator == equal do -:127: { 26:128: if var auto cn = asNullExp(ce.right) do 2:129: condition = ce.left; 22:130: else do if var auto ie = getIntLiteral(ce.right) do 8:131: if ie.value == 0 do 3:132: condition = ce.left; -:133: } -:134: } -:135: -:136: var AssignExpression* ae; 16:137: var auto bs = asBlockStatement(node.thenBlock); 16:138: if bs && bs.statements.length == 1 do 6:139: if var auto es = asExpressionStatement(bs.statements[0]) do 3:140: ae = asAssignExp(es.expression); -:141: 16:142: if condition && ae && ae.left == condition do 3:143: warn($unit.filename, node.startPos , "statement can be rewritten `%s ?= %s;`", -:144: format(ae.left).ptr, format(ae.right).ptr); 16:145: } -:146: 85:147: @override function visitType(Type* node){} -:148:} -:149: -:150:/* Warn if `e1 ? e1 else e2` can rewritten `e1 ? e2` -:151: -:152:1. the lexical pass is faster : less tokens to lex, less AST nodes. -:153:2. the backend produces better code because `e1` is only evaluated once. -:154:*/ -:155:@final class SuggestCondExpVisitor : PostSemaLintVisitor -:156:{ -:157: @override function visitConditionalExpression(ConditionalExpression* node) -:158: { 7:159: node.accept(this); 7:160: if node.isShorthandSyntax do 1:161: return; -:162: var Expression* condition; 12:163: if var auto ce = node.condition:CmpExpression* do -:164: { 6:165: if ce.operator == notEqual do -:166: { 12:167: if var auto cn = asNullExp(ce.right) do 5:168: condition = ce.left; 2:169: else do if var auto ie = getIntLiteral(ce.right) do 1:170: if ie.value == 0 do 1:171: condition = ce.left; -:172: } -:173: } 6:174: if condition && condition == node.thenExpression do 2:175: warn($unit.filename, node.startPos , "conditional expression can be shortened to `%s ? %s`", -:176: format(node.thenExpression).ptr, format(node.elseExpression).ptr); 6:177: } -:178: 86:179: @override function visitType(Type* node){} -:180:} -:181: -:182:/* Warn if a CondExp can be rewritten using an AndAndExp or an OrOrExp -:183: -:184:1. the lexical pass is faster : less tokens to lex, less AST nodes. -:185:2. the backend produces less PHI nodes -:186: -:187:problems: rewrites of the CmpExpression prevent to output the exact suggestion -:188:*/ -:189:@final class SuggestCondToLogical : PostSemaLintVisitor -:190:{ -:191: @override function visitConditionalExpression(ConditionalExpression* node) -:192: { 7:193: node.accept(this); 7:194: const auto be1 = asBoolExp(node.thenExpression); 7:195: const auto be2 = asBoolExp(node.elseExpression); -:196: var s8* msg; 7:197: if be2 && !be1 do -:198: { 2:199: if !be2.value do 1:200: msg = "expression `e1 ? e2 else false` can be rewritten as `e1 && e2`"; -:201: else do 1:202: msg = "expression `e1 ? e2 else true` can be rewritten as `!(e1 && e2)`"; -:203: } 5:204: else do if be1 && !be2 do -:205: { 2:206: if !be1.value do 1:207: msg = "expression `e1 ? false else e2` can be rewritten as `!(e1) && e2`"; -:208: else do 1:209: msg = "expression `e1 ? true else e2` can be rewritten as `e1 || e2`"; -:210: } 11:211: if msg do warn($unit.filename, node.startPos, msg); 7:212: } -:213: 86:214: @override function visitType(Type* node){} -:215:} -:216: -:217:/* warn if `{exp; break;}` can be rewritten `break exp;` -:218: -:219:This syntax is an extension of the classic `break` statement, -:220:the suggestion helps getting used to it. -:221:*/ -:222:@final class SuggestBreakExpVisitor : LintVisitor -:223:{ -:224: @override function visitBlockStatement(BlockStatement* node) -:225: { 47:226: if node.statements.length == 2 do -:227: { 6:228: var auto es = asExpressionStatement(node.statements.ptr[0]); 6:229: var auto bs = node.statements.ptr[1]:BreakStatement*; 6:230: var auto cs = node.statements.ptr[1]:ContinueStatement*; 6:231: var auto fs = bs ? cs; 6:232: if es && fs && !fs.expression do 2:233: warn($unit.filename, node.startPos , "the block can be rewritten `%s %s`", -:234: tokenString[fs.kind].ptr, format(es).ptr); -:235: } 47:236: node.accept(this); 47:237: } -:238: 70:239: @override function visitExpression(Expression* node){} -:240: 70:241: @override function visitType(Type* node){} -:242:} -:243: -:244:/* Warns if an import is not used -:245: -:246:Unused imports matching to files founds in a path defined from a CLI -I argument -:247:are unecessarily and lazily opened, parsed, and contextualized. -:248: -:249:Other unused imports always add a small overhead during pre-semantic -:250: -:251:problems: aliases to basic types. -:252:*/ -:253:@final class UnusedImportsVisitor : PostSemaLintVisitor -:254:{ -:255: var ImportElement*[+][+] imported; -:256: -:257: @destructor function destroy() -:258: { 12:259: imported.decref; 12:260: } -:261: -:262: function checkSymbol(Symbol* s) -:263: { 151:264: var auto u = s.parentUnit(); 151:265: if u:u8* != $unit:u8* do -:266: { 15:267: foreach var auto sc in imported do 29:268: foreach var auto i in sc do -:269: { -:270: //printf("testing %s, symu= %p importedu=%p\n", s.name.text().ptr, u.symbol, i); 86:271: if i && i.terminalUnit && i.terminalUnit:u8* == u.symbol:u8* do 6:272: i = null; -:273: } -:274: } 151:275: } -:276: -:277: function popScopeAndCheck() -:278: { 105:279: foreach const auto i in imported[$-1] do 11:280: if i && i.terminalUnit do -:281: { 3:282: var auto u = i.terminalUnit.astNode:UnitDeclaration*; 3:283: warn($unit.filename, i.startPos , "import `%s` is never used", format(u.identifiers).ptr); -:284: } 105:285: imported.length -= 1; 105:286: } -:287: -:288: function pushScope(Symbol* sym) -:289: { 105:290: imported.length++; -:291: function walkChildren(Symbol* ss) -:292: { 131:293: foreach const auto s in ss.children do 360:294: if var auto ie = s:ImportElement* do -:295: { 26:296: if ie.terminalUnit:u8* != $unit.symbol:u8* do -:297: { -:298: // ignores rtl.sx 14:299: if ie.startPos.line != 0 do -:300: { -:301: //printf("added %s %p\n", format(ie.terminalUnit.astNode).ptr, ie.terminalUnit); 11:302: imported[$-1] ~= ie; -:303: } -:304: } 26:305: walkChildren(s); -:306: } 131:307: } 105:308: walkChildren(sym); 105:309: } -:310: -:311: @override function visitAliasDeclaration(AliasDeclaration* node) -:312: { 7:313: node.accept(this); 7:314: if node.sourceSymbol do 1:315: checkSymbol(node.sourceSymbol); 7:316: } -:317: -:318: @override function visitBlockStatement(BlockStatement* node) -:319: { 49:320: if node.symbol do -:321: { 48:322: pushScope(node.symbol); 48:323: node.accept(this); 48:324: popScopeAndCheck(); -:325: } 1:326: else do node.accept(this); 49:327: } -:328: -:329: @override function visitDeclaration(Declaration* node) -:330: { 133:331: if node.kind == $import do 4:332: return; 129:333: if !node.symbol || node.symbol.kind in [SymbolKind.$alias, SymbolKind.variable] do -:334: { 73:335: visitConcreteDeclaration(node); 73:336: return; -:337: } 56:338: if node.symbol.recurseGuard do 3:339: return; 53:340: node.symbol.recurseGuard++; 53:341: var auto u = node.symbol.parentUnit():u8*; 53:342: const auto isImported = u != $unit:u8*; 53:343: checkSymbol(node.symbol); 53:344: if !isImported do -:345: { 45:346: pushScope(node.symbol); 45:347: visitConcreteDeclaration(node); 45:348: popScopeAndCheck(); -:349: } 53:350: node.symbol.recurseGuard--; 53:351: } -:352: -:353: @override function visitExpression(Expression* node) -:354: { 235:355: if node.symbol do 97:356: checkSymbol(node.symbol); 235:357: visitConcreteExpression(node); 235:358: } -:359: -:360: @override function visitUnitDeclaration(UnitDeclaration* node) -:361: { 12:362: assert(!$unit); 12:363: $unit = node; 12:364: pushScope(node.symbol); 12:365: node.accept(this); 12:366: popScopeAndCheck(); 12:367: } -:368: -:369: @override function visitType(Type* node) -:370: { 133:371: if node.kind != $null do 133:372: visitConcreteType(node); 133:373: } -:374: -:375: @override function visitTypeClass(TypeClass* node) -:376: { 1:377: visitDeclaration(node.declaration); 1:378: } -:379: -:380: @override function visitTypeEnum(TypeEnum* node) -:381: { 1:382: visitDeclaration(node.declaration); 1:383: } -:384: -:385: @override function visitTypeFunction(TypeFunction* node) -:386: { 2:387: visitDeclaration(node.declaration); 2:388: } -:389: -:390: @override function visitTypeIdentifier(TypeIdentifier* node) -:391: { 46:392: if var auto t = node.resolved() do 46:393: if var auto td = t:TypeDeclared* do 18:394: visitDeclaration(td.declaration); 23:395: node.accept(this); 23:396: } -:397: -:398: @override function visitTypeStruct(TypeStruct* node) -:399: { 2:400: visitDeclaration(node.declaration); 2:401: } -:402: -:403: @override function visitTypeUnion(TypeUnion* node) -:404: { 1:405: visitDeclaration(node.declaration); 1:406: } -:407:} -:408: -:409:/* Warn if an explicit alloca is not used -:410: -:411:1. the initializer can lead to codegen more than required -:412:2. reveals strange stuffs, going from relics of old code that's been refactored -:413: to bugs in the program logic -:414:*/ -:415:@final class UnusedLocalsVisitor : PostSemaLintVisitor -:416:{ -:417: var VariableDeclaration*[+] vds; -:418: -:419: @destructor function destroy() -:420: { 1:421: vds.decref; 1:422: } -:423: -:424: @override function visitForeachStatement(ForeachStatement* node) -:425: { 10:426: var auto vc = node.variables[0]; -:427: // drop the counter of "counted-only" loops because -:428: // there's no way of preventing the warning 10:429: if node.variables.length == 1 && isLoopCounter in vc.flags do -:430: { 2:431: foreach var auto vd in vds do 5:432: if vd && vc:u8* == vd:u8* do 2:433: break vd = null; -:434: } 10:435: node.accept(this); 10:436: } -:437: -:438: @override function visitFunctionDeclaration(FunctionDeclaration* node) -:439: { 19:440: if !node.body do 1:441: return; -:442: -:443: var usize added; 18:444: const auto entryLen = vds.length; 18:445: vds.length += node.allocas.length; 18:446: foreach const auto vd in node.allocas do 58:447: if isTemp !in vd.flags do -:448: { 43:449: vds[entryLen + added++] = vd; -:450: } 18:451: vds.length = entryLen + added; -:452: 18:453: node.accept(this); -:454: 18:455: foreach const auto vd in vds[entryLen .. $] do 43:456: if vd do 8:457: warn($unit.filename, vd.startPos , "%s `%s` is never used", vd.isConst() ? "constant" else "variable", vd.name.text().ptr); -:458: 18:459: vds.length = entryLen; 18:460: } -:461: -:462: @override function visitIdentExpression(IdentExpression* node) -:463: { 90:464: foreach var auto vd in vds do 454:465: if node.symbol && vd && node.symbol:u8* == vd.symbol:u8* do 33:466: break vd = null; 90:467: } -:468: -:469: @override function visitRefCountExpression(RefCountExpression* node) -:470: { 1:471: visitConcreteExpression(node.expression); 1:472: } -:473: -:474: @override function visitSliceExpression(SliceExpression* node) -:475: { 7:476: if node.assignRhs do 1:477: visitConcreteExpression(node.assignRhs); 7:478: node.accept(this); 7:479: } -:480: 85:481: @override function visitType(Type* node){} -:482:} -:483: -:484:/* Assignments in `assert()` is a code smell. -:485: -:486:While they can be perfectly legit, `assert()` are conditionally compiled. -:487:Conditionally compiled `assignments` should be done in version blocks -:488:or in conditionally imported CUs. -:489:*/ -:490:@final class AssignInAssertVisitor : LintVisitor -:491:{ -:492: var bool inAssert; -:493: -:494: function check(Expression* node) -:495: { 13:496: if inAssert do warn($unit.filename, node.startPos , -:497: "assignment `%s` depends on CLI arg `--check=asserts`, use `version` statements for more explicit conditional compilation", format(node).ptr); 12:498: } -:499: -:500: @override function visitAssertStatement(AssertStatement* node) -:501: { 1:502: const auto o = inAssert; 1:503: inAssert = !node.isStatic; 1:504: node.accept(this); 1:505: inAssert = o; 1:506: } -:507: -:508: @override function visitExpression(Expression* node) -:509: { 189:510: const auto op = node.operator; 189:511: if TokenType.ass <= op && op <= TokenType.optAss do 12:512: check(node); 189:513: visitConcreteExpression(node); 189:514: } -:515: 70:516: @override function visitType(Type* node){} -:517:} -:518: -:519:/* Warn when slices are fully resliced -:520: -:521:That generates useless code -:522:*/ -:523:@final class ResliceVisitor : PostSemaLintVisitor -:524:{ -:525: @override function visitSliceExpression(SliceExpression* node) -:526: { 7:527: if !node.expression.type.asTypeSlice() do -:528: { 4:529: node.accept(this); 4:530: return; -:531: } -:532: var bool doWarn; -:533: // someSlice[] 3:534: if !node.sourceLength do -:535: { 1:536: doWarn = true; -:537: } -:538: // someSlice[0 .. {$|someSlice.length}] 4:539: else do if var auto s = node.expression.symbol do -:540: { 2:541: var auto re = asRangeExp(node.range); 2:542: var auto ie = getIntLiteral(re.left); 2:543: var auto de = asDollarExp(re.right); 2:544: var auto le = asLengthExp(de ? de.expression else re.right); 2:545: if ie && ie.value == 0 && le && le.expression.symbol:u8* == s:u8* do 2:546: doWarn = true; -:547: } 3:548: if doWarn do 3:549: warn($unit.filename, node.startPos , "full slicing of `%s` is useless because it is already a slice", format(node.expression).ptr); 3:550: node.accept(this); 3:551: } -:552: 86:553: @override function visitType(Type* node){} -:554:} -:555: -:556:/* Warn when a loop variable could be `const` -:557: -:558:Using `const` instead of `var` reduces the number of loads to 1. -:559:*/ -:560:@final class LoopInvariantVisitor : PostSemaLintVisitor -:561:{ -:562: struct ForeachVar -:563: { -:564: var VariableDeclaration* vd; -:565: var usize used; -:566: } -:567: -:568: var ForeachVar[+] fvs; -:569: -:570: @destructor function destroy() -:571: { 1:572: fvs.decref; 1:573: } -:574: -:575: function tryUnsetVariable(Expression* node) -:576: { 5:577: foreach const auto fv in fvs do 5:578: if fv.vd && node.symbol:u8* == fv.vd.symbol:u8* do -:579: { -:580: //printf("unset %s\n", format(v[0]).ptr); 5:581: fv.vd = null; -:582: } 5:583: } -:584: -:585: @override function visitExpression(Expression* node) -:586: { 264:587: if fvs.length do switch node.operator do -:588: { -:589: on ass .. optAss do 2:590: tryUnsetVariable((node:BinaryExpression*).left); -:591: on eopAt, plusPlus, minMin, eopPreInc, eopPreDec do 2:592: tryUnsetVariable((node:UnaryExpression*).expression); 41:593: else do {} -:594: } 219:595: visitConcreteExpression(node); 219:596: } -:597: -:598: @override function visitCallExpression(CallExpression* node) -:599: { 3:600: visitConcreteExpression(node.expression); 6:601: if var auto fd = node.fd do -:602: { 3:603: foreach const auto i; const auto p in fd.parameters do -:604: { 3:605: if !p.isVar() do 2:606: continue; 1:607: if i < node.arguments.length do 1:608: tryUnsetVariable(node.arguments.ptr[i]); -:609: } -:610: } 3:611: } -:612: -:613: @override function visitForeachStatement(ForeachStatement* node) -:614: { -:615: var usize numAdded; 10:616: foreach const auto vd in node.variables do -:617: { 18:618: if isLoopCounter !in vd.flags && !vd.isConst() && vd.escapeIndex == -1 do -:619: { 7:620: fvs ~= (vd, 0:usize); 7:621: numAdded++; -:622: //printf("added %s\n", format(vd).ptr); -:623: } -:624: } 10:625: node.accept(this); 10:626: if numAdded do -:627: { 7:628: foreach const auto fv in fvs[$-numAdded .. $] do -:629: { 7:630: if fv.vd && fv.used > 1 do 2:631: warn($unit.filename, fv.vd.startPos , -:632: "loop variable `%s` is never used as a lvalue and could be set `const` instead of `var`", -:633: format(fv.vd).ptr); -:634: } 7:635: fvs.length -= numAdded; -:636: } 10:637: } -:638: -:639: @override function visitIdentExpression(IdentExpression* node) -:640: { 85:641: foreach const auto fv in fvs do 31:642: if fv.vd && node.symbol:u8* == fv.vd.symbol:u8* do -:643: { -:644: //printf("incremented uses of %s\n", format(v[0]).ptr); 14:645: fv.used++; -:646: } 85:647: } -:648: 86:649: @override function visitType(Type* node){} -:650:} <<<<<< EOF # path=src/styx/parser.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/parser.sx -: 1:unit styx.parser; -: 2: -: 3:@private import -: 4: system, -: 5: styx.session, -: 6: styx.position, -: 7: styx.token, -: 8: styx.lexer, -: 9: styx.ast.base, -: 10: styx.ast.declarations, -: 11: styx.ast.expressions, -: 12: styx.ast.statements, -: 13: styx.ast.types, -: 14: ; -: 15: -: 16:/** -: 17:Styx parser -: 18: -: 19:The function `parseUnitDeclaration` consumes the lexer to produce th AST of a whole unit. -: 20:The parser owns the unit but not the lexer. -: 21:*/ -: 22:struct Parser -: 23:{ -: 24:protection (private) -: 25: -: 26: var Lexer* lexer; -: 27: var UnitDeclaration* $unit; -: 28: var bool hasErrors; -: 29: var bool isHeader; -: 30: var Token* current; -: 31: -: 32: function warn(const s8* specifier; ...): auto -: 33: { -: 34: var va_list lst; 21: 35: var auto va = (&lst):u8*; 21: 36: va_start(va); 21: 37: session.warn(lexer.filename(), current.position, specifier, &lst); 21: 38: va_end(va); 21: 39: return null; -: 40: } -: 41: -: 42: function error(const s8* specifier; AstNode* partialNode; ...): auto -: 43: { 1014: 44: if partialNode do partialNode.free(); 716: 45: hasErrors = true; -: 46: var va_list lst; 716: 47: var auto va = (&lst):u8*; 716: 48: va_start(va); 716: 49: session.error(lexer.filename(), current.position, specifier, &lst); 716: 50: va_end(va); 716: 51: return null; -: 52: } -: 53: -: 54: function expected(const ExtendedTokenType expected; AstNode* partialNode): auto -: 55: { 154: 56: assert(current.type != expected); 287: 57: if partialNode do partialNode.free(); 154: 58: session.error(lexer.filename(), current.position, "expected `%s` instead of `%s`", tokenString[expected].ptr, current.type == id ? current.text().ptr else tokenString[current.type].ptr); 154: 59: return null; -: 60: } -: 61: -: 62: function unexpected(AstNode* partialNode): auto -: 63: { 854: 64: if partialNode do partialNode.free(); 436: 65: session.error(lexer.filename(), current.position, "unexpected `%s`", current.type == id ? current.text().ptr else tokenString[current.type].ptr); 436: 66: return null; -: 67: } -: 68: -: 69: function freeAndNull(AstNode* partialNode): auto -: 70: { 1544: 71: if partialNode do partialNode.free(); 774: 72: return null; -: 73: } -: 74: -: 75: function advance(): Token* -: 76: { 396020: 77: lexer.popFront(); 396020: 78: current = lexer.front(); 396020: 79: return current; -: 80: } -: 81: -: 82: function lookupNext(): Token* -: 83: { 8311: 84: return lexer.lookup(); -: 85: } -: 86: -: 87: /*function skipPair(const TokenType start; const TokenType stop): bool -: 88: { -: 89: assert(current.type == start); -: 90: var usize cnt; -: 91: while true do -: 92: { -: 93: const auto tt = current.type; -: 94: cnt += tt == start; -: 95: cnt -= tt == stop; -: 96: if tt == eof do -: 97: break; -: 98: advance(); -: 99: if cnt == 0 do -: 100: break; -: 101: } -: 102: return cnt == 0; -: 103: }*/ -: 104: -: 105: function parseBinaryExpression[TT, T, ParseSameBin, ParsePredBin]() : Expression* -: 106: { 988386: 107: var auto p = current.position; 988386: 108: var Expression* result = ParsePredBin(); 988386: 109: if current.type == TT do -: 110: { 4450: 111: advance(); 4450: 112: result = (new T).create(p, result, ParseSameBin()); -: 113: } 988386: 114: return result; -: 115: } -: 116: -: 117:protection (public) -: 118: -: 119: /// Constructs the parser with the lexer that contains the tokens to parse. -: 120: @constructor function create(Lexer* lexer; bool isHeader = false) -: 121: { 1205: 122: this.isHeader = isHeader; 1205: 123: this.lexer = lexer; 1205: 124: } -: 125: -: 126: /// Free the whole AST -: 127: @destructor function destroy() -: 128: { 685: 129: $unit?.free(); 685: 130: } -: 131: -: 132: /// Rerturns: the unit obtained after parsing -: 133: function getUnit(): UnitDeclaration* -: 134: { 2323: 135: return $unit; -: 136: } -: 137: -: 138: /// Returns: an `Expression*` if an `AddExpression*` can be parsed otherwise `null` -: 139: function parseAddExpression(): Expression* -: 140: { 79098: 141: return parseBinaryExpression:[TokenType.plus, AddExpression, echo(func), parseModExpression](); -: 142: } -: 143: -: 144: /// Returns: an `AggregateDeclaration*` if one can be parsed otherwise `null` -: 145: function parseAggregateDeclaration(AggregateDeclaration* result): AggregateDeclaration* -: 146: { 996: 147: if !advance().isTok:[id]() do 3: 148: return expected(TokenType.id, result); 993: 149: result.name = current; 993: 150: if advance().isTok:[leftSquare]() do 63: 151: result.genericParameters = parseGenericParameters(); 993: 152: if current.isTok:[colon]() do -: 153: { 311: 154: if !advance().isTok:[id]() do 3: 155: return expected(TokenType.id, result); 308: 156: while true do -: 157: { 636: 158: if var auto t = parseType() do 317: 159: result.inheritanceList ~= t; 1: 160: else do return freeAndNull(result); 317: 161: if current.isTok:[comma]() do -: 162: { 11: 163: if !advance().isTok:[id]() do 1: 164: return expected(TokenType.id, result); 10: 165: continue; -: 166: } 306: 167: break; -: 168: } -: 169: } 988: 170: if current.isTok:[semiColon]() do -: 171: { 14: 172: advance(); 14: 173: return result; -: 174: } 974: 175: if !current.isTok:[leftCurly]() do 4: 176: return expected(TokenType.leftCurly, result); 970: 177: advance(); 1940: 178: if var auto d = parseDeclarations() do 966: 179: result.body = d; 4: 180: else do return freeAndNull(result); 966: 181: if !current.isTok:[rightCurly]() do 3: 182: return expected(TokenType.rightCurly, result); 963: 183: result.stopPos = current.position; 963: 184: advance(); 963: 185: return result; -: 186: } -: 187: -: 188: /// Returns: an `Expression*` if an `AndAndExpression` can be parsed otherwise `null` -: 189: function parseAndAndExpression(): Expression* -: 190: { 72227: 191: return parseBinaryExpression:[TokenType.andAnd, AndAndExpression, echo(func), parseInExpression](); -: 192: } -: 193: -: 194: /// Returns: an `Expression*` if an `AndExpression` can be parsed otherwise `null` -: 195: function parseAndExpression(): Expression* -: 196: { 72505: 197: return parseBinaryExpression:[TokenType.amp, AndExpression, echo(func), parseCmpExpression](); -: 198: } -: 199: -: 200: /// Returns: an `AliasDeclaration*` if one can be parsed otherwise `null` -: 201: function parseAliasDeclaration(): Declaration* -: 202: { 403: 203: var auto p = current.position; 403: 204: if !advance().isTok:[id]() do 1: 205: return expected(TokenType.id, null); 402: 206: var auto n = current; 402: 207: advance(); 402: 208: if current.isTok:[eopLambda]() do -: 209: { 22: 210: advance(); 22: 211: var auto e = parseExpression(); 22: 212: if !e do 1: 213: return null; 21: 214: if !current.isTok:[semiColon]() do 2: 215: return expected(TokenType.semiColon, e); 19: 216: advance(); 19: 217: return (new ExpressionAlias).create(p, n, e); -: 218: } 380: 219: if !current.isTok:[ass]() do 2: 220: return expected(TokenType.ass, null); 378: 221: var auto result = (new AliasDeclaration).create(p, n); 378: 222: switch advance().type do -: 223: { -: 224: on TokenType.$apply do -: 225: { 216: 226: if var auto ae = parseApplyExpression() do 107: 227: result.exp = ae; 1: 228: else do return freeAndNull(result); -: 229: } -: 230: on TokenType.$function do -: 231: { 86: 232: if var auto e = parseLambdaOrTypeExpression() do 40: 233: result.exp = e; 3: 234: else do return freeAndNull(result); -: 235: } -: 236: else do -: 237: { 454: 238: if var auto t = parseType() do 225: 239: result.type = t; 2: 240: else do return freeAndNull(result); -: 241: } -: 242: } 372: 243: if !current.isTok:[semiColon]() do 2: 244: return expected(TokenType.semiColon, result); 370: 245: advance(); 370: 246: return result; -: 247: } -: 248: -: 249: /// Returns: an `ArrayExpression*` if one can be parsed otherwise `null` -: 250: function parseArrayExpression(): ArrayExpression* -: 251: { 380: 252: assert(current.isTok:[leftSquare]()); -: 253: 380: 254: var auto result = (new ArrayExpression).create(current.position); 380: 255: advance(); -: 256: var StackAppender:[64,Expression*] eapp; 380: 257: while true do -: 258: { 2418: 259: if current.isTok:[rightSquare]() do 22: 260: break; 4792: 261: if var auto e = parseExpression() do -: 262: { 2392: 263: eapp.append(e); 2392: 264: if current.isTok:[comma]() do 2038: 265: continue advance(); 354: 266: if current.isTok:[rightSquare]() do 353: 267: break; -: 268: } 5: 269: return unexpected(result); -: 270: } 375: 271: advance(); 375: 272: result.items = eapp.reclaim(); 375: 273: return result; -: 274: } -: 275: -: 276: /// Returns: an `ApplyExpression*` if one can be parsed otherwise `null` -: 277: function parseApplyExpression(): ApplyExpression* -: 278: { 124: 279: var auto p = current.position; 124: 280: if !advance().isTok:[leftParen]() do 1: 281: return expected(TokenType.leftParen, null); 123: 282: advance(); 123: 283: var auto g = parseExpression(); 123: 284: if !g do 2: 285: return null; 121: 286: if !current.isTok:[comma]() do 1: 287: return expected(TokenType.comma, g); 120: 288: advance(); -: 289: var StackAppender:[64,Expression*] eapp; 120: 290: while true do -: 291: { 346: 292: if var auto e = parseExpression() do -: 293: { 170: 294: eapp.append(e); 170: 295: if current.isTok:[comma]() do 53: 296: continue advance(); 117: 297: if current.isTok:[rightParen]() do 115: 298: break advance(); -: 299: } 5: 300: return unexpected(g); -: 301: } 115: 302: return (new ApplyExpression).create(p, g, eapp.reclaim()); -: 303: } -: 304: -: 305: /// Returns: an `AsmExpression*` if one can be parsed otherwise `null` -: 306: function parseAsmExpression(): AsmExpression* -: 307: { 29: 308: var auto result = (new AsmExpression).create(current.position); 29: 309: advance(); 29: 310: if !current.isTok:[leftParen]() do 1: 311: return expected(TokenType.leftParen, result); 28: 312: advance(); 28: 313: if !current.isTok:[stringLiteral]() do 2: 314: return expected(TokenType.stringLiteral, result); 26: 315: result.code = current; 26: 316: advance(); 26: 317: if current.isTok:[comma]() do -: 318: { 16: 319: advance(); 16: 320: if !current.isTok:[stringLiteral]() do 1: 321: return expected(TokenType.stringLiteral, result); 15: 322: result.constraint = current; 15: 323: advance(); -: 324: } 25: 325: while true do -: 326: { 39: 327: if current.isTok:[rightParen]() do 23: 328: break; 16: 329: if !current.isTok:[comma]() do 1: 330: return expected(TokenType.comma, result); 15: 331: advance(); 30: 332: if var auto e = parseExpression() do 14: 333: result.arguments ~= e; 1: 334: else do return freeAndNull(result); -: 335: } 23: 336: advance(); 23: 337: if current.isTok:[colon]() do -: 338: { 11: 339: advance(); 22: 340: if var auto t = parseType() do 10: 341: result.returnType = t; 1: 342: else do return freeAndNull(result); -: 343: } 12: 344: else do result.returnType = TypeVoid.instance(); 22: 345: return result; -: 346: } -: 347: -: 348: /// Returns: an `AssertStatement*` if one can be parsed otherwise `null` -: 349: function parseAssertStatement(bool isStatic): AssertStatement* -: 350: { 2381: 351: var auto result = (new AssertStatement).create(current.position); 2381: 352: result.isStatic = isStatic; 2381: 353: if !advance().isTok:[leftParen]() do 1: 354: return expected(TokenType.leftParen, result); 2380: 355: advance(); 4760: 356: if var auto e = parseExpression() do -: 357: { 2378: 358: result.expression = e; 2378: 359: if current.isTok:[comma]() do -: 360: { 40: 361: advance(); 40: 362: result.message = parseExpression(); -: 363: } 2378: 364: if !current.isTok:[rightParen]() do 2: 365: return expected(TokenType.rightParen, result); 2376: 366: if !advance().isTok:[semiColon]() do 1: 367: return expected(TokenType.semiColon, result); 2375: 368: advance(); 2375: 369: return result; -: 370: } 2: 371: return freeAndNull(result); -: 372: } -: 373: -: 374: /// Returns: an `Expression*` if an `AssignExpression` or a `CondExpression` can be parsed otherwise `null` -: 375: function parseExpression(): Expression* -: 376: { 70752: 377: var auto p = current.position; 70752: 378: var auto result = parseOrOrExpression(); 70752: 379: if !result do 173: 380: return null; -: 381: -: 382: function parseAssignExpression(AssignExpression* ae): AssignExpression* -: 383: { 6990: 384: ae = ae.create(p, result); 6990: 385: advance(); 6990: 386: if (ae.right = parseExpression()) do 6981: 387: return ae; 9: 388: return freeAndNull(ae); -: 389: } -: 390: 70579: 391: switch current.type do -: 392: { 5571: 393: on TokenType.ass do result = parseAssignExpression(new AssignExpression); 14: 394: on TokenType.mulAss do result = parseAssignExpression(new MulAssignExpression); 53: 395: on TokenType.divAss do result = parseAssignExpression(new DivAssignExpression); 5: 396: on TokenType.modAss do result = parseAssignExpression(new ModAssignExpression); 244: 397: on TokenType.plusAss do result = parseAssignExpression(new AddAssignExpression); 140: 398: on TokenType.minusAss do result = parseAssignExpression(new SubAssignExpression); 10: 399: on TokenType.ampAss do result = parseAssignExpression(new AndAssignExpression); 10: 400: on TokenType.pipeAss do result = parseAssignExpression(new OrAssignExpression); 10: 401: on TokenType.xorAss do result = parseAssignExpression(new XorAssignExpression); 5: 402: on TokenType.lshiftAss do result = parseAssignExpression(new LShiftAssignExpression); 5: 403: on TokenType.rshiftAss do result = parseAssignExpression(new RShiftAssignExpression); 863: 404: on TokenType.tidAss do result = parseAssignExpression(new ConcatAssignExpression); 60: 405: on TokenType.optAss do result = parseAssignExpression(new OptAssignExpression); -: 406: on TokenType.dotDot do -: 407: { 958: 408: advance(); 1916: 409: if var auto right = parseExpression() do 953: 410: return (new RangeExpression).create(p, result, right); 5: 411: return freeAndNull(result); -: 412: } -: 413: on TokenType.qmark do -: 414: { 606: 415: advance(); 606: 416: var auto ce = (new ConditionalExpression).create(p, result); 1212: 417: if var auto left = parseExpression() do 604: 418: ce.thenExpression = left; 2: 419: else do return freeAndNull(ce); 604: 420: if current.isTok:[$else]() do -: 421: { 561: 422: advance(); 1122: 423: if var auto right = parseExpression() do 560: 424: ce.elseExpression = right; 1: 425: else do return freeAndNull(ce); -: 426: } 603: 427: result = ce; -: 428: } 62025: 429: else do {} -: 430: } 69618: 431: return result; -: 432: } -: 433: -: 434: /// Returns: an `Attribute*` if at least one can be parsed otherwise `null` -: 435: function parseAttribute(): Attribute* -: 436: { 1614: 437: var auto p = current.position; 1614: 438: advance(); 1614: 439: const auto isUser = current.isTok:[at](); 1747: 440: if isUser do advance(); 1614: 441: if !current.isTokKeyword() && !current.isTok:[id]() do 3: 442: return error("expected keyword or identifier after `@` or `@@`", null); 1611: 443: var auto result = (new Attribute).create(p, current, isUser); 1611: 444: if !advance().isTok:[leftParen]() do 1378: 445: return result; 233: 446: advance(); 233: 447: while true do -: 448: { 538: 449: if var auto e = parseExpression() do -: 450: { 267: 451: result.arguments ~= e; 267: 452: if current.isTok:[rightParen]() do 229: 453: break advance(); 38: 454: if current.isTok:[comma]() do 36: 455: continue advance(); 2: 456: return unexpected(result); -: 457: } 2: 458: return freeAndNull(result); -: 459: } 229: 460: return result; -: 461: } -: 462: -: 463: /// Returns: an `Attributes*` if at least one `Attribute*` can be parsed otherwise `null` -: 464: function parseAttributes(): Attributes* -: 465: { 3310: 466: var auto result = (new Attributes).create(current.position); -: 467: -: 468: function checkNoArgAttrib(NoArgAttribute targetAttribute; s8* argError; s8* dupError): bool -: 469: { 1824: 470: if targetAttribute in result.noArgAttributes do 11: 471: warn(dupError, result); 1824: 472: advance(); 1824: 473: advance(); -: 474: // not really required per grammar 1824: 475: if current.isTok:[leftParen]() do -: 476: { 11: 477: error(argError, result); 11: 478: return false; -: 479: } 1813: 480: result.noArgAttributes += targetAttribute; 1813: 481: return true; -: 482: } -: 483: -: 484: 3310: 485: while current.isTok:[at]() do -: 486: { 10314: 487: switch lookupNext().text() do -: 488: { -: 489: on "abstract" do -: 490: { 19: 491: if !checkNoArgAttrib(NoArgAttribute.atAbstract, "`@abstract` takes no argument", "duplicated `@abstract` attribute") do 1: 492: return null; 18: 493: continue; -: 494: } -: 495: on "constructor" do -: 496: { 222: 497: if !checkNoArgAttrib(NoArgAttribute.atConstructor, "`@constructor` takes no argument", "duplicated `@constructor` attribute") do 1: 498: return null; 221: 499: continue; -: 500: } -: 501: on "destructor" do -: 502: { 96: 503: if !checkNoArgAttrib(NoArgAttribute.atDestructor, "`@destructor` takes no argument", "duplicated `@destructor` attribute") do 1: 504: return null; 95: 505: continue; -: 506: } -: 507: on "final" do -: 508: { 186: 509: if !checkNoArgAttrib(NoArgAttribute.atFinal, "`@final` takes no argument", "duplicated `@final` attribute") do 1: 510: return null; 185: 511: continue; -: 512: } -: 513: on "noinit" do -: 514: { 69: 515: if !checkNoArgAttrib(NoArgAttribute.atNoinit, "`@noinit` takes no argument", "duplicated `@noinit` attribute") do 1: 516: return null; 68: 517: continue; -: 518: } -: 519: on "noopt" do -: 520: { 6: 521: if !checkNoArgAttrib(NoArgAttribute.atNoopt, "`@noopt` takes no argument", "duplicated `@noopt` attribute") do 1: 522: return null; 5: 523: continue; -: 524: } -: 525: on "noreturn" do -: 526: { 6: 527: if !checkNoArgAttrib(NoArgAttribute.atNoReturn, "`@noreturn` takes no argument", "duplicated `@noreturn` attribute") do 1: 528: return null; 5: 529: continue; -: 530: } -: 531: on "override" do -: 532: { 887: 533: if !checkNoArgAttrib(NoArgAttribute.atOverride, "`@override` takes no argument", "duplicated `@override` attribute") do 1: 534: return null; 886: 535: continue; -: 536: } -: 537: on "return" do -: 538: { 28: 539: if !checkNoArgAttrib(NoArgAttribute.atReturn, "`@return` takes no argument", "duplicated `@return` attribute") do 1: 540: return null; 27: 541: continue; -: 542: } -: 543: on "tls" do -: 544: { 6: 545: if !checkNoArgAttrib(NoArgAttribute.atTLS, "`@tls` takes no argument", "duplicated `@tls` attribute") do 1: 546: return null; 5: 547: continue; -: 548: } -: 549: on "virtual" do -: 550: { 299: 551: if !checkNoArgAttrib(NoArgAttribute.atVirtual, "`@virtual` takes no argument", "duplicated `@virtual` attribute") do 1: 552: return null; 298: 553: continue; -: 554: } 1614: 555: else do {} -: 556: } -: 557: 1614: 558: var auto a = parseAttribute(); 1614: 559: if !a do 7: 560: return freeAndNull(result); 1607: 561: if a.isUser do 129: 562: continue result.atUser ~= a; -: 563: -: 564: function checkAttribute(var Attribute* other; bool ParamCountFail; -: 565: s8* argError; s8* dupError): bool -: 566: { 1474: 567: if ParamCountFail do -: 568: { 12: 569: freeAndNull(a); 12: 570: error(argError, result); 12: 571: return false; -: 572: } 1462: 573: if other do -: 574: { 10: 575: freeAndNull(other); 10: 576: warn(dupError); -: 577: } 1462: 578: other = a; 1462: 579: return true; -: 580: } -: 581: 1478: 582: const auto i = a.identifier.iptr(); 1478: 583: const auto t = a.identifier.type; 1478: 584: if t == TokenType.$asm do -: 585: { 7: 586: if !checkAttribute(result.atAsm, a.arguments.length != 1, "`@asm` takes one argument", "duplicated `@asm` attribute") do 1: 587: return null; -: 588: } 1471: 589: else do if i == deprecatedToken().iptr() do -: 590: { 20: 591: if !checkAttribute(result.atDeprecated, a.arguments.length > 1, "`@deprecated` takes no or one argument", "duplicated `@deprecated` attribute") do 1: 592: return null; -: 593: } 1451: 594: else do if i == foreignToken().iptr() do -: 595: { 639: 596: if !checkAttribute(result.atForeign, a.arguments.length != 0, "`@foreign` takes no argument", "duplicated `@foreign` attribute") do 1: 597: return null; -: 598: } 812: 599: else do if i == inlineToken().iptr() do -: 600: { 188: 601: if !checkAttribute(result.atInline, a.arguments.length > 1, "`@inline` takes no or one argument", "duplicated `@inline` attribute") do 1: 602: return null; -: 603: } 624: 604: else do if i == llvmToken().iptr() do -: 605: { 31: 606: if !checkAttribute(result.atLLVM, a.arguments.length > 1, "`@LLVM` takes no or one argument", "duplicated `@LLVM` attribute") do 1: 607: return null; -: 608: } 593: 609: else do if i == operatorToken().iptr() do -: 610: { 120: 611: if !checkAttribute(result.atOperator, a.arguments.length == 0, "`@operator` takes at least one argument", "duplicated `@operator` attribute") do 1: 612: return null; -: 613: } 473: 614: else do if t == TokenType.$overload do -: 615: { 12: 616: if !checkAttribute(result.atOverload, a.arguments.length != 1, "`@overload` takes one argument", "duplicated `@overload` attribute") do 1: 617: return null; -: 618: } 461: 619: else do if i == unittestToken().iptr() do -: 620: { 363: 621: if !checkAttribute(result.atUnittest, a.arguments.length != 0, "`@unittest` takes no argument", "duplicated `@unittest` attribute") do 1: 622: return null; -: 623: } 98: 624: else do if i == publicToken().iptr() || i == privateToken().iptr() || 9: 625: i == protectedToken().iptr() || i == strictToken().iptr() do -: 626: { 94: 627: if !checkAttribute(result.atProtection, a.arguments.length != 0, "protection attribute takes no argument", "only a single protection attribute allowed") do 4: 628: return null; -: 629: } -: 630: else do -: 631: { 4: 632: freeAndNull(a); 4: 633: return error("invalid builtin attribute", result); -: 634: } -: 635: } 3276: 636: return result; -: 637: } -: 638: -: 639: /// Returns: a `BlockStatement*` if one can be parsed otherwise `null` -: 640: function parseBlockStatement(): BlockStatement* -: 641: { 14773: 642: var auto result = (new BlockStatement).create(current.position); 14773: 643: const auto isNotSingle = current.isTok:[leftCurly](); 14773: 644: result.isSingle = !isNotSingle; 14773: 645: if isNotSingle do -: 646: { 8961: 647: advance(); 8961: 648: if current.isTok:[rightCurly]() do -: 649: { 816: 650: result.stopPos = current.position; 816: 651: advance(); 816: 652: return result; -: 653: } -: 654: } -: 655: var StackAppender:[64,Statement*] sapp; 13957: 656: while true do -: 657: { 35131: 658: var auto p = current.position; -: 659: var Statement* s; 35131: 660: if current.isTok:[eof]() do 2: 661: return expected(TokenType.rightCurly, result); 35129: 662: if !current.isTok:[$version]() do 70146: 663: if var auto d = parseDeclaration() do 7112: 664: s = (new DeclarationStatement).create(p, d); 35129: 665: s ?= parseStatement(); 35309: 666: if !s do return freeAndNull(result); 34949: 667: result.stopPos = current.position; 34949: 668: if !isNotSingle do -: 669: { 5800: 670: result.statements ~= s; 5800: 671: return result; -: 672: } 29149: 673: sapp.append(s); 29149: 674: if current.isTok:[rightCurly]() do -: 675: { 7975: 676: advance(); 7975: 677: result.statements = sapp.reclaim(); 7975: 678: return result; -: 679: } -: 680: } -: 681: } -: 682: -: 683: /// Returns: the input argument if its class of control flow statement can be parsed and `null` otherwise -: 684: function parseBreakContinueOrGoto(LabeledFlowControl* result): LabeledFlowControl* -: 685: { 1003: 686: advance(); 1003: 687: if current.isTok:[at]() do -: 688: { 36: 689: if !advance().isTok:[id]() do 5: 690: return error("expected label identifier following `@`", result); 31: 691: result.$label = current; 31: 692: if advance().isTok:[comma]() do -: 693: { 14: 694: advance(); 14: 695: result.expression = parseExpression(); -: 696: } -: 697: } -: 698: else do -: 699: { 967: 700: if result.kind == TokenType.$goto do 2: 701: return error("expected `@label` after `goto`", result); 965: 702: if !current.isTok:[semiColon]() do 282: 703: result.expression = parseExpression(); -: 704: } 996: 705: if !current.isTok:[semiColon]() do 2: 706: return expected(TokenType.semiColon, result); 994: 707: result.stopPos = current.position; 994: 708: advance(); 994: 709: return result; -: 710: } -: 711: -: 712: /// Returns: a `CallExpression*` if one can be parsed otherwise `null` -: 713: function parseCallExpression(var Position p; Expression* callee): CallExpression* -: 714: { 13627: 715: var CallExpression* result = (new CallExpression).create(p, callee); 13627: 716: if advance().isTok:[rightParen]() do -: 717: { 4585: 718: advance(); 4585: 719: return result; -: 720: } -: 721: var StackAppender:[64,Expression*] eapp; 9042: 722: while true do -: 723: { 31678: 724: if var auto e = parseExpression() do -: 725: { 15838: 726: eapp.append(e); 15838: 727: switch current.type do -: 728: { -: 729: on rightParen do -: 730: { 9039: 731: advance(); 9039: 732: result.arguments = eapp.reclaim(); 9039: 733: return result; -: 734: } 6797: 735: on comma do continue advance(); 2: 736: else do return unexpected(result); -: 737: } -: 738: } 1: 739: return freeAndNull(result); -: 740: } -: 741: } -: 742: -: 743: /// Returns: an `AggregateDeclaration*` if a `ClassDeclaration` can be parsed otherwise `null` -: 744: function parseClassDeclaration(): AggregateDeclaration* -: 745: { 504: 746: return parseAggregateDeclaration((new ClassDeclaration).create(current.position)); -: 747: } -: 748: -: 749: /// Returns: a `ContinueOnStatement*` if one can be parsed otherwise `null` -: 750: function parseContinueOnStatement(): ContinueOnStatement* -: 751: { 36: 752: var auto result = (new ContinueOnStatement).create(current.position); 36: 753: advance(); 36: 754: advance(); 36: 755: if current.isTok:[$else]() do -: 756: { 13: 757: result.isElseTargeted = true; 13: 758: advance(); -: 759: } 23: 760: else do if !current.isTok:[semiColon]() do 16: 761: result.targetMatch = parseExpression(); 36: 762: if !current.isTok:[semiColon]() do 3: 763: return expected(TokenType.semiColon, result); 33: 764: result.stopPos = current.position; 33: 765: advance(); 33: 766: return result; -: 767: } -: 768: -: 769: /// Returns: an `Expression*` if a `CmpExpression` can be parsed otherwise `null` -: 770: function parseCmpExpression(): Expression* -: 771: { 72505: 772: var auto p = current.position; 72505: 773: var auto result = parseRShiftExpression(); 72505: 774: if isRelational(current.type) do -: 775: { 4539: 776: const auto tt = current.type; 4539: 777: advance(); 4539: 778: result = (new CmpExpression).create(p, tt, result, parseRShiftExpression()); -: 779: } 72505: 780: return result; -: 781: } -: 782: -: 783: /// Returns: an `Expression*` if a `ConcatExpression` can be parsed otherwise `null` -: 784: function parseConcatExpression(): Expression* -: 785: { 77157: 786: return parseBinaryExpression:[TokenType.tidle, ConcatExpression, echo(func), parseSubExpression](); -: 787: } -: 788: -: 789: /// Returns: a `Declaration*` if one can be parsed otherwise `null` -: 790: function parseDeclaration(): Declaration* -: 791: { 44344: 792: var auto attribs = current.isTok:[at]() ? parseAttributes() else null; -: 793: var StorageClasses stc; 44344: 794: if current.isTokStorageClass() do 8295: 795: stc = parseStorageClasses(); -: 796: -: 797: function attribCheckAndReturnNull(): auto -: 798: { 28317: 799: if attribs do 2: 800: error("unexpected attribute", attribs); 28317: 801: return null; -: 802: } -: 803: -: 804: function stcDeclError(): auto -: 805: { 20: 806: error("unexpected storage class(es)", attribs); 20: 807: return null; -: 808: } -: 809: 44344: 810: switch current.type do -: 811: { -: 812: on $label do -: 813: { 21: 814: if stc != 0 do return stcDeclError(); 38: 815: if var auto result = parseLabelDeclaration() do -: 816: { 17: 817: result.attributes = attribs; 17: 818: return result; -: 819: } 2: 820: return attribCheckAndReturnNull(); -: 821: } -: 822: on $enum do -: 823: { 460: 824: if stc != 0 do return stcDeclError(); 916: 825: if var auto result = parseEnumDeclaration() do -: 826: { 446: 827: result.attributes = attribs; 446: 828: return result; -: 829: } 12: 830: return attribCheckAndReturnNull(); -: 831: } -: 832: on $class do -: 833: { 1008: 834: if var auto result = parseClassDeclaration() do -: 835: { 495: 836: result.attributes = attribs; 495: 837: result.stc = stc; 495: 838: return result; -: 839: } 9: 840: return attribCheckAndReturnNull(); -: 841: } -: 842: on $struct do -: 843: { 914: 844: if var auto result = parseStructDeclaration() do -: 845: { 450: 846: result.attributes = attribs; 450: 847: result.stc = stc; 450: 848: return result; -: 849: } 7: 850: return attribCheckAndReturnNull(); -: 851: } -: 852: on $union do -: 853: { 70: 854: if var auto result = parseUnionDeclaration() do -: 855: { 32: 856: result.attributes = attribs; 32: 857: result.stc = stc; 32: 858: return result; -: 859: } 3: 860: return attribCheckAndReturnNull(); -: 861: } -: 862: on $function do -: 863: { -: 864: // if var / const in stc then it's a variable declaration -: 865: // var static function(){} -: 866: // static var function(){} 6041: 867: if (StorageClass.$var in stc) || (StorageClass.$const in stc) do 16: 868: continue on id; 12050: 869: if var auto result = parseFunctionDeclaration(false) do -: 870: { 5836: 871: result.attributes = attribs; 5836: 872: if result.isVar() do 19: 873: stc += StorageClass.$var; 5836: 874: result.stc = stc; 5836: 875: return result; -: 876: } 189: 877: return attribCheckAndReturnNull(); -: 878: } -: 879: on $import do -: 880: { 157: 881: if stc != 0 do return stcDeclError(); 310: 882: if var auto result = parseImportDeclaration() do -: 883: { 142: 884: result.attributes = attribs; 142: 885: return result; -: 886: } 13: 887: return attribCheckAndReturnNull(); -: 888: } -: 889: on $protection do -: 890: { 178: 891: if stc != 0 do return stcDeclError(); 352: 892: if var auto result = parseProtectionDeclaration() do -: 893: { 171: 894: result.attributes = attribs; 171: 895: return result; -: 896: } 5: 897: return attribCheckAndReturnNull(); -: 898: } -: 899: on id do -: 900: { 19780: 901: if stc != 0 do // variable decl need a storage, otherwise it's a expr. -: 902: { 15258: 903: if var auto result = parseVariableDeclaration(true) do -: 904: { 7561: 905: result.attributes = attribs; 7561: 906: result.stc = stc; 7561: 907: return result; -: 908: } 68: 909: error("unexpected storage class(es)", null); -: 910: } 12219: 911: return attribCheckAndReturnNull(); -: 912: } -: 913: on $alias do -: 914: { 405: 915: if stc != 0 do return stcDeclError(); 806: 916: if var auto result = parseAliasDeclaration() do -: 917: { 389: 918: result.attributes = attribs; 389: 919: return result; -: 920: } 14: 921: return attribCheckAndReturnNull(); -: 922: } -: 923: on $version do -: 924: { 119: 925: if stc != 0 do return stcDeclError(); 234: 926: if var auto result = parseVersionBlockDeclaration() do -: 927: { 105: 928: result.attributes = attribs; 105: 929: return result; -: 930: } 12: 931: return attribCheckAndReturnNull(); -: 932: } -: 933: on $overload do -: 934: { 60: 935: if stc != 0 do return stcDeclError(); 116: 936: if var auto result = parseOverloadDelaration() do -: 937: { 51: 938: result.attributes = attribs; 51: 939: return result; -: 940: } 7: 941: return attribCheckAndReturnNull(); -: 942: } -: 943: on $assert do -: 944: { 2384: 945: if stc != [StorageClass.$static] do -: 946: { 2074: 947: if stc != 0 do return stcDeclError(); 2068: 948: return attribCheckAndReturnNull(); -: 949: } 313: 950: var auto p = current.position; 626: 951: if var auto as = parseAssertStatement(true) do 312: 952: return (new StaticAssertDeclaration).create(p, as); 1: 953: return attribCheckAndReturnNull(); -: 954: } -: 955: else do -: 956: { 19746: 957: if current.isTokBasicType() || current.isTok:[$auto]() || current.isTok:[$echo]() || 13856: 958: current.isTok:[leftParen]() do // unambiguous type form: var(s8) v = ... 5980: 959: continue on id; 13776: 960: if stc != 0 do return stcDeclError(); 13756: 961: return attribCheckAndReturnNull(); -: 962: } -: 963: } -: 964: } -: 965: -: 966: /// Returns: a `Declarations*` if one can be parsed otherwise `null` -: 967: function parseDeclarations(): Declarations* -: 968: { -: 969: var StackAppender:[64,Declaration*] dapp; 2233: 970: var auto result = (new Declarations).create(current.position); 13266: 971: while true do switch current.type do -: 972: { -: 973: on eof, rightCurly do -: 974: { 1859: 975: result.items = dapp.reclaim(); 1859: 976: return result; -: 977: } -: 978: else do -: 979: { 18348: 980: if var auto d = parseDeclaration() do 8800: 981: continue dapp.append(d); 374: 982: return unexpected(result); -: 983: } -: 984: } -: 985: } -: 986: -: 987: /// Returns: an `Expression*` if a `DivExpression` can be parsed otherwise `null` -: 988: function parseDivExpression(): Expression* -: 989: { 79458: 990: return parseBinaryExpression:[TokenType.div, DivExpression, echo(func), parseMulExpression](); -: 991: } -: 992: -: 993: /// Returns: an `EchoExpression*` if one can be parsed otherwise `null` -: 994: function parseEchoExpression(): Expression* -: 995: { 1102: 996: var auto result = (new EchoExpression).create(current.position); 1102: 997: if !advance().isTok:[leftParen]() do 1: 998: return expected(TokenType.leftParen, result); 1101: 999: advance(); 1101:1000: if !current.isTok:[id]() && !current.isTokKeyword() do 2:1001: return expected(TokenType.id, result); 1099:1002: result.command = current; 1099:1003: if advance().isTok:[rightParen]() do -:1004: { 876:1005: advance(); 876:1006: return result; -:1007: } 223:1008: if !current.isTok:[comma]() do 1:1009: return expected(TokenType.comma, result); 222:1010: advance(); 222:1011: while true do -:1012: { 726:1013: if var auto ep = parseExpression() do 360:1014: result.arguments ~= ep; 3:1015: else do return error("invalid echo argument", result); 360:1016: switch current.type do -:1017: { -:1018: on rightParen do -:1019: { 217:1020: advance(); 217:1021: return result; -:1022: } 141:1023: on comma do continue advance(); 2:1024: else do return unexpected(result); -:1025: } -:1026: } -:1027: } -:1028: -:1029: /// Returns: an `EnumDeclaration*` if one can be parsed otherwise `null` -:1030: function parseEnumDeclaration(): EnumDeclaration* -:1031: { 458:1032: var auto result = (new EnumDeclaration).create(current.position); 458:1033: if !advance().isTok:[id]() do 2:1034: return expected(TokenType.id, result); 456:1035: result.name = current; 456:1036: if advance().isTok:[colon]() do -:1037: { 240:1038: advance(); 240:1039: result.type = parseType(); -:1040: } 456:1041: if current.isTok:[ass]() do -:1042: { 303:1043: var auto p = current.position; 303:1044: advance(); 606:1045: if var auto e = parseExpression() do -:1046: { 302:1047: var auto em = (new EnumMember).create(p, result.name, e); 302:1048: result.members = [em]; 302:1049: result.flags[isEponymous] = true; -:1050: } 1:1051: else do return freeAndNull(result); 302:1052: if !current.isTok:[semiColon]() do 1:1053: return expected(TokenType.semiColon, result); 301:1054: advance(); 301:1055: return result; -:1056: } 153:1057: if !current.isTok:[leftCurly]() do 2:1058: return expected(TokenType.leftCurly, result); 151:1059: advance(); 151:1060: while true do -:1061: { 1448:1062: if var auto em = parseEnumMember() do -:1063: { 718:1064: result.members ~= em; 718:1065: if current.isTok:[comma]() do -:1066: { 636:1067: advance(); 636:1068: if current.isTok:[rightCurly]() do 63:1069: break; 573:1070: continue; -:1071: } 82:1072: if current.isTok:[rightCurly]() do 82:1073: break; -:1074: } 6:1075: return error("invalid enum member", result); -:1076: } 145:1077: advance(); 145:1078: return result; -:1079: } -:1080: -:1081: /// Returns: an `EnumMember*` if one can be parsed otherwise `null` -:1082: function parseEnumMember(): EnumMember* -:1083: { -:1084: var Attributes* a; 725:1085: if current.isTok:[at]() && !(a = parseAttributes()) do return null; 723:1086: if !current.isTok:[id]() do 3:1087: return expected(TokenType.id, a); 720:1088: var auto result = (new EnumMember).create(current.position, current); 720:1089: result.attributes = a; 720:1090: advance(); 720:1091: if current.isTok:[comma]() || current.isTok:[rightCurly]() do 632:1092: return result; 88:1093: if current.isTok:[ass]() do -:1094: { 87:1095: advance(); 174:1096: if var auto e = parseExpression() do -:1097: { 87:1098: result.value = e; 87:1099: if current.isTok:[comma]() || current.isTok:[rightCurly]() do 86:1100: return result; -:1101: } -:1102: } 2:1103: return error("invalid enum member", result); -:1104: } -:1105: -:1106: /// Returns: an `ExpressionStatement*` if one can be parsed otherwise `null` -:1107: function parseExpressionStatement(): ExpressionStatement* -:1108: { 13534:1109: var auto p = current.position; 13534:1110: var auto e = parseExpression(); 13534:1111: if current.isTok:[semiColon]() do -:1112: { 13490:1113: advance(); 26964:1114: if e do return (new ExpressionStatement).create(p, e); -:1115: } 60:1116: const auto m = current.position.line > p.line ? "missing `;` to terminate expression statement" else "invalid expression"; 60:1117: return error(m, e); -:1118: } -:1119: -:1120: /// Returns: a `ForeachStatement*` if one can be parsed otherwise `null` -:1121: function parseForeachStatement(): ForeachStatement* -:1122: { 659:1123: var auto result = (new ForeachStatement).create(current.position); 659:1124: advance(); 659:1125: const auto needRightParen = current.isTok:[leftParen](); 659:1126: if needRightParen do 211:1127: advance(); 659:1128: while current.isTokStorageClass() do -:1129: { 815:1130: const auto stc = parseStorageClasses(); 1630:1131: if var auto vd = parseVariableDeclaration(false) do -:1132: { 813:1133: vd.context = VariableDeclarationContext.localForeach; 813:1134: result.variables ~= vd; 813:1135: vd.stc = stc; -:1136: } 2:1137: else do return error("invalid `foreach` variable", result); 813:1138: if current.isTok:[$in]() || current.isTok:[rightParen]() do 646:1139: break; 167:1140: const auto isComma = current.isTok:[comma](); 167:1141: if isComma || current.isTok:[semiColon]() do -:1142: { 165:1143: if isComma do 2:1144: return error("foreach variables must be separated using `;`, not `,`", result); 163:1145: if !advance().isTokStorageClass() do 1:1146: return unexpected(result); 162:1147: continue; -:1148: } 2:1149: return unexpected(result); -:1150: } 652:1151: if result.variables.length == 0 do 6:1152: return error("expected at least one `foreach` variable", result); 646:1153: if needRightParen do -:1154: { 201:1155: if !current.isTok:[rightParen]() do 1:1156: return expected(TokenType.rightParen, result); 200:1157: result.hasParens = true; 200:1158: advance(); -:1159: } 645:1160: if !current.isTok:[$in]() do 1:1161: return expected(TokenType.$in, result); 644:1162: advance(); 1288:1163: if var auto e = parseExpression() do 642:1164: result.expression = e; 2:1165: else do return error("invalid `foreach` enumerable", result); -:1166: 642:1167: if !current.isTok:[$do]() do 3:1168: return expected(TokenType.$do, result); 639:1169: advance(); 639:1170: return (result.blockStatement = parseBlockStatement()) ? result else freeAndNull(result); -:1171: } -:1172: -:1173: /// Returns: a `FunctionDeclaration*` if one can be parsed otherwise `null` -:1174: function parseFunctionDeclaration(bool asType): FunctionDeclaration* -:1175: { 6215:1176: var auto result = (new FunctionDeclaration).create(current.position); 6215:1177: if !advance().isTok:[id]() do -:1178: { 170:1179: if !asType do return expected(TokenType.id, result); -:1180: } -:1181: else do -:1182: { 6047:1183: result.name = current; 6047:1184: advance(); 6047:1185: if !asType && current.isTok:[dot]() && lookupNext().isTok:[id]() do -:1186: { 11:1187: advance(); 11:1188: const auto pa = result.name; 11:1189: result.name = current; 11:1190: result.externalAggregate = pa; 11:1191: advance(); -:1192: } -:1193: } 6213:1194: if current.isTok:[leftSquare]() do 108:1195: result.genericParameters = parseGenericParameters(); 6213:1196: if !current.isTok:[leftParen]() do 10:1197: return expected(TokenType.leftParen, result); 6203:1198: advance(); 6203:1199: while !current.isTok:[rightParen]() do -:1200: { 6023:1201: if current.isTok:[ellipsis]() do -:1202: { 92:1203: result.flags += isCeeVariadic; 92:1204: advance(); 92:1205: break; -:1206: } -:1207: var StorageClasses stc; 5931:1208: var auto at = current.isTok:[at]() ? parseAttributes() else null; 5931:1209: if current.isTokStorageClass() do 1977:1210: stc = parseStorageClasses(); 11862:1211: if var auto vd = parseVariableDeclaration(false, result.parameters.length == 0) do -:1212: { 5920:1213: vd.context = VariableDeclarationContext.parameter; 5920:1214: vd.stc = stc; 5920:1215: vd.attributes = at; 5920:1216: result.parameters ~= vd; 5920:1217: if current.isTok:[semiColon]() do 2411:1218: continue advance(); 3509:1219: break; -:1220: } 11:1221: return freeAndNull(result); -:1222: } 6192:1223: if !current.isTok:[rightParen]() do 3:1224: return expected(TokenType.rightParen, result); 6189:1225: if advance().isTok:[colon]() do -:1226: { 2746:1227: advance(); 2746:1228: if current.isTok:[$var]() do -:1229: { 22:1230: advance(); 22:1231: result.stc += $var; -:1232: } 5492:1233: if var auto returnType = parseType() do 2742:1234: result.returnType = returnType; 4:1235: else do return error("invalid return type", result); -:1236: } 3443:1237: else do result.returnType = TypeVoid.instance(); 6185:1238: if asType do 181:1239: return result; 6004:1240: if current.isTok:[ass]() do -:1241: { 14:1242: advance(); 14:1243: if !current.isTok:[$asm]() do 1:1244: return expected(TokenType.$asm, result); 13:1245: advance(); 26:1246: if var auto e = parseExpression() do 10:1247: result.asmBody = e; 3:1248: else do return freeAndNull(result); 10:1249: if !current.isTok:[semiColon]() do 1:1250: return expected(TokenType.semiColon, result); 9:1251: advance(); 9:1252: return result; -:1253: } 5990:1254: if !current.isTok:[leftCurly]() && !current.isTok:[semiColon]() do 1:1255: return error("expected `;` or `{` to start `function` body", result); 5989:1256: if current.isTok:[leftCurly]() do -:1257: { 10542:1258: if var auto bs = parseBlockStatement() do 5109:1259: result.body = bs; 162:1260: else do return error("invalid `function` body", result); -:1261: } 718:1262: else do advance(); 5827:1263: return result; -:1264: } -:1265: -:1266: /// Returns: a `GenericParameters*` if one can be parsed otherwise `null` -:1267: function parseGenericParameters(): GenericParameters* -:1268: { 171:1269: var auto result = new GenericParameters; 171:1270: advance(); 171:1271: while true do -:1272: { -:1273: var Type* valueType; 387:1274: const auto isId = current.isTok:[id](); 387:1275: if !isId || lookupNext().isTok:[id]() do -:1276: { 238:1277: if !(valueType = parseType()) do 1:1278: return freeAndNull(result); -:1279: } 386:1280: if current.isTok:[id]() do -:1281: { 384:1282: result.parameters ~= (new GenericParameter).create(current.position, current, valueType); 384:1283: advance(); -:1284: } 2:1285: else do return unexpected(result); 384:1286: switch current.type do -:1287: { 216:1288: on comma do continue advance(); 167:1289: on rightSquare do break advance(); 1:1290: else do return unexpected(result); -:1291: } -:1292: } 167:1293: return result; -:1294: } -:1295: -:1296: /// Returns: an `IfElseStatement*` if one can be parsed otherwise `null` -:1297: function parseIfElseStatement(): IfElseStatement* -:1298: { 5427:1299: var auto result = (new IfElseStatement).create(current.position); 5427:1300: advance(); -:1301: // for if (VarDecl) 5427:1302: const auto needRightParen = current.isTok:[leftParen]() && lookupNext().isTokStorageClass(); 5442:1303: if needRightParen do advance(); 5427:1304: if current.isTokStorageClass() do -:1305: { 486:1306: const StorageClasses stc = parseStorageClasses(); 972:1307: if var auto vd = parseVariableDeclaration(false) do -:1308: { 484:1309: vd.context = VariableDeclarationContext.localIf; 484:1310: result.ifVariable = vd; 484:1311: vd.stc = stc; -:1312: } -:1313: } 4941:1314: else do result.condition = parseExpression(); 5427:1315: if !result.condition && !result.ifVariable do 16:1316: return error("invalid `if` condition", result); 5411:1317: if needRightParen do -:1318: { 13:1319: if !current.isTok:[rightParen]() do 1:1320: return expected(TokenType.rightParen, result); 12:1321: advance(); 12:1322: result.hasParens = true; -:1323: } 5410:1324: if !current.isTok:[$do]() do 3:1325: return expected(TokenType.$do, result); 5407:1326: advance(); 10814:1327: if var auto bs = parseBlockStatement() do 5405:1328: result.thenBlock = bs; 2:1329: else do return freeAndNull(result); 5405:1330: if current.isTok:[$else]() do -:1331: { 801:1332: if !advance().isTok:[$do]() do 1:1333: return expected(TokenType.$do, result); 800:1334: advance(); 1600:1335: if var auto bs = parseBlockStatement() do 799:1336: result.elseBlock = bs; 1:1337: else do return freeAndNull(result); -:1338: } 5403:1339: return result; -:1340: } -:1341: -:1342: /// Returns: an `ImportDeclaration*` if one can be parsed otherwise `null` -:1343: function parseImportDeclaration(): ImportDeclaration* -:1344: { 155:1345: var auto result = (new ImportDeclaration).create(current.position); 155:1346: advance(); 155:1347: while true do -:1348: { 410:1349: var auto t = parseTypeIdentifier(false); 410:1350: if !t do 10:1351: return error("invalid `import` declaration", result); 400:1352: result.importList ~= t; 400:1353: if current.isTok:[$in]() do -:1354: { 22:1355: result.isSelective = true; 22:1356: advance(); 44:1357: if var auto t0 = parseTypeIdentifier(false) do -:1358: { 21:1359: result.importList ~= t0; 21:1360: if current.isTok:[semiColon]() do 20:1361: break advance(); 1:1362: return error("invalid `import` declaration", result); -:1363: } -:1364: } 379:1365: if current.isTok:[comma]() do -:1366: { 284:1367: advance(); 284:1368: if current.isTok:[semiColon]() do 29:1369: break advance(); 255:1370: continue; -:1371: } 95:1372: if current.isTok:[semiColon]() do 93:1373: break advance(); 2:1374: return unexpected(result); -:1375: } 142:1376: return result; -:1377: } -:1378: -:1379: /// Returns: an `Expression*` if a `IndexExpression` or a `SliceExpression` can be parsed otherwise `null` -:1380: function parseIndexOrSliceExpression(var Position p; Expression* e): Expression* -:1381: { 2403:1382: advance(); 2403:1383: if current.isTok:[rightSquare]() do -:1384: { 161:1385: var auto se = (new SliceExpression).create(p, e); 161:1386: advance(); 161:1387: return se; -:1388: } 2242:1389: else do if current.isTok:[plus]() && lookupNext().isTok:[rightSquare]() && 17:1390: (e.operator == id || e.operator == $echo || e.operator == dot || e.operator == eopSlice || e.operator == mul) do -:1391: { 17:1392: var auto se = (new SliceExpression).create(p, e); 17:1393: se.tryAsTypeRca = true; 17:1394: advance(); 17:1395: advance(); 17:1396: return se; -:1397: } 2225:1398: var auto s = parseExpression(); -:1399: var Expression* t; 2225:1400: var auto re = s?.asRangeExp(); 2225:1401: if re && current.isTok:[rightSquare]() do -:1402: { 574:1403: advance(); 574:1404: return (new SliceExpression).create(p, e, re); -:1405: } 1651:1406: else do if s do -:1407: { 1651:1408: var auto ie = (new IndexExpression).create(p, e, s); 1651:1409: while true do -:1410: { 1663:1411: if current.isTok:[rightSquare]() do -:1412: { 1649:1413: advance(); 1649:1414: return ie; -:1415: } 14:1416: if current.isTok:[comma]() do -:1417: { 13:1418: advance(); 26:1419: if var auto x = parseExpression() do 12:1420: continue ie.indexes ~= x; -:1421: } 2:1422: t = ie; 2:1423: break; -:1424: } -:1425: } 2:1426: return error("invalid index or slice expression", t); -:1427: } -:1428: -:1429: /// Returns: an `Expression*` if a `InExpression*` can be parsed otherwise `null` -:1430: function parseInExpression(): Expression* -:1431: { 72227:1432: var auto p = current.position; 72227:1433: var auto result = parseOrExpression(); 72227:1434: const auto negated = current.isTok:[not](); 72227:1435: if negated do 44:1436: advance(); 72227:1437: if current.isTok:[$in]() do -:1438: { 190:1439: advance(); 190:1440: result = (new InExpression).create(p, parseOrExpression(), result, negated); -:1441: } 72227:1442: return result; -:1443: } -:1444: -:1445: /// Returns: an `Expression*` if a `LShiftExpression` can be parsed otherwise `null` -:1446: function parseLShiftExpression(): Expression* -:1447: { 77063:1448: return parseBinaryExpression:[TokenType.lShift, LShiftExpression, echo(func), parseConcatExpression](); -:1449: } -:1450: -:1451: /// Returns: a `LabelDeclaration*` if one can be parsed otherwise `null` -:1452: function parseLabelDeclaration(): LabelDeclaration* -:1453: { 19:1454: var auto result = (new LabelDeclaration).create(current.position); 19:1455: if !advance().isTok:[id]() do 1:1456: return expected(TokenType.id, result); 18:1457: result.name = current; 18:1458: if !advance().isTok:[semiColon]() do 1:1459: return expected(TokenType.semiColon, result); 17:1460: advance(); 17:1461: return result; -:1462: } -:1463: -:1464: /// Returns: a `LambdaExpression*` if one can be parsed, a `TypeExpression*` containing -:1465: /// a `TypeFunction*` id one can be parsed and otherwise `null` -:1466: function parseLambdaOrTypeExpression(): Expression* -:1467: { 81:1468: var auto fd = parseFunctionDeclaration(true); 81:1469: if !fd do 2:1470: return error("invalid lambda expression", null); 79:1471: const auto t = current.type; 79:1472: if t == leftSquare || t == mul do -:1473: { 2:1474: var Type* tt = (new TypeFunction).create(fd, true); 2:1475: if (tt = parseTypeModified(fd.startPos, tt)) do 1:1476: return (new TypeExpression).create(fd.startPos, tt); 1:1477: return freeAndNull(tt); -:1478: } 77:1479: if t == dot || t == comma || t == rightParen || t == semiColon do 40:1480: return (new TypeExpression).create(fd.startPos, (new TypeFunction).create(fd, true)); 37:1481: if !current.isTok:[eopLambda]() do 2:1482: return expected(ExtendedTokenType.eopLambda, fd); -:1483: 35:1484: advance(); 35:1485: var auto p = current.position; -:1486: var BlockStatement* bs; -:1487: var Expression* e; 35:1488: if current.isTok:[leftCurly]() do -:1489: { 22:1490: if var auto stmt = parseStatement() do 10:1491: bs = *((&stmt):BlockStatement**); -:1492: } 24:1493: else do if (e = parseExpression()) do -:1494: { -:1495: var Statement* stmt; 21:1496: bs = (new BlockStatement).create(p); 21:1497: bs.stopPos = current.position; 21:1498: if isTypeVoid(fd.returnType) do 2:1499: stmt = (new ExpressionStatement).create(e.startPos, e); -:1500: else do -:1501: { 19:1502: var auto rs = (new ReturnStatement).create(e.startPos, e); 19:1503: rs.stopPos = bs.stopPos; 19:1504: stmt = rs; -:1505: } 21:1506: bs.statements~= stmt; -:1507: } 35:1508: if bs do -:1509: { 31:1510: fd.body = bs; 31:1511: fd.name = Token.generateIdentifierFromPos(fd.startPos, "__lambda"); 31:1512: return (new LambdaExpression).create(fd.startPos, fd, e); -:1513: } 4:1514: else do return error("invalid lambda expression", fd); -:1515: } -:1516: -:1517: /// Returns: an `Expression*` if a `MulExpression` can be parsed otherwise `null` -:1518: function parseMulExpression(): Expression* -:1519: { 79877:1520: return parseBinaryExpression:[TokenType.mul, MulExpression, echo(func), parseUnaryExpression](); -:1521: } -:1522: -:1523: /// Returns: an `Expression*` if a `ModExpression` can be parsed otherwise `null` -:1524: function parseModExpression(): Expression* -:1525: { 79167:1526: return parseBinaryExpression:[TokenType.mod, ModExpression, echo(func), parseDivExpression](); -:1527: } -:1528: -:1529: /// Returns: a `OnMatchStatement*` if one can be parsed otherwise `null` -:1530: function parseOnMatchStatement(): OnMatchStatement* -:1531: { 1707:1532: var auto result = (new OnMatchStatement).create(current.position); 1707:1533: advance(); 1707:1534: const auto needRightParen = current.isTok:[leftParen](); 1707:1535: if needRightParen do 13:1536: advance(); 1707:1537: while true do -:1538: { 1925:1539: var auto e = parseExpression(); 1925:1540: if !e do 2:1541: return error("invalid `on` match expression", result); 1923:1542: result.onMatchExpressions ~= e; 1923:1543: if current.isTok:[rightParen]() && needRightParen do 10:1544: break advance(); 1913:1545: else do if !needRightParen && current.isTok:[$do]() do 1693:1546: break; 220:1547: else do if current.isTok:[comma]() do 218:1548: continue advance(); -:1549: else do 2:1550: return unexpected(result); -:1551: } 1703:1552: if !current.isTok:[$do]() do 1:1553: return expected(TokenType.$do, result); 1702:1554: advance(); 1702:1555: return (result.blockStatement = parseBlockStatement()) ? result else freeAndNull(result); -:1556: } -:1557: -:1558: /// Returns: an `Expression*` if a `OrExpression` can be parsed otherwise `null` -:1559: function parseOrExpression(): Expression* -:1560: { 72472:1561: return parseBinaryExpression:[TokenType.pipe, OrExpression, echo(func), parseXorExpression](); -:1562: } -:1563: -:1564: /// Returns: an `Expression*` if a `OrOrExpression` can be parsed otherwise `null` -:1565: function parseOrOrExpression(): Expression* -:1566: { 71234:1567: return parseBinaryExpression:[TokenType.orOr, OrOrExpression, echo(func), parseAndAndExpression](); -:1568: } -:1569: -:1570: /// Returns: a `ProtectionDeclaration*` if one can be parsed otherwise `null` -:1571: function parseOverloadDelaration(): OverloadDeclaration* -:1572: { 58:1573: var auto result = (new OverloadDeclaration).create(current.position); 58:1574: if !advance().isTok:[id]() do 1:1575: return expected(TokenType.id, result); 57:1576: result.name = current; 57:1577: if advance().isTok:[colon]() do -:1578: { 6:1579: advance(); 12:1580: if var auto t = parseType() do 5:1581: result.base = t; 1:1582: else do return freeAndNull(result); -:1583: } 56:1584: if !current.isTok:[leftCurly]() do 1:1585: return expected(TokenType.leftCurly, result); 55:1586: advance(); -:1587: var StackAppender:[64,Expression*] eapp; 55:1588: while true do -:1589: { 234:1590: if var auto e = parseExpression() do 115:1591: eapp.append(e); 2:1592: else do return freeAndNull(result); 115:1593: if current.isTok:[comma]() do -:1594: { 77:1595: advance(); 77:1596: if current.isTok:[rightCurly]() do 15:1597: break advance(); 62:1598: continue; -:1599: } 38:1600: if current.isTok:[rightCurly]() do 36:1601: break advance(); 2:1602: return expected(TokenType.rightCurly, result); -:1603: } 51:1604: result.members = eapp.reclaim(); 51:1605: return result; -:1606: } -:1607: -:1608: /// Returns: an `Expression*` if a primary expression can be parsed otherwise `null` -:1609: function parsePrimaryExpression(): Expression* -:1610: { 79899:1611: var auto curTok = current; 79899:1612: var auto p = curTok.position; 79899:1613: switch curTok.type do -:1614: { -:1615: on $apply do -:1616: { 16:1617: var auto ae = parseApplyExpression(); 16:1618: return ae ? error("invalid `apply` expression", null); -:1619: } -:1620: on dollar do -:1621: { 119:1622: advance(); 119:1623: return (new DollarExpression).create(p); -:1624: } -:1625: on $asm do -:1626: { 29:1627: var auto ae = parseAsmExpression(); 29:1628: return ae ? error("invalid `asm` expression", null); -:1629: } -:1630: on $super do -:1631: { 117:1632: advance(); 117:1633: return (new SuperExpression).create(p); -:1634: } -:1635: on TokenType.$this do -:1636: { 719:1637: advance(); 719:1638: return (new ThisExpression).create(p); -:1639: } -:1640: on $echo do -:1641: { 1102:1642: var auto ec = parseEchoExpression(); 1102:1643: return ec ? error("invalid `echo` expression", null); -:1644: } -:1645: on $static do -:1646: { -:1647: // drop `static`. It is not used in the context of TypeFunction comparisons. 2:1648: advance(); 2:1649: continue on; -:1650: } -:1651: on $function do -:1652: { 38:1653: return parseLambdaOrTypeExpression(); -:1654: } -:1655: on leftParen do -:1656: { 3429:1657: advance(); 6858:1658: if var auto e = parseExpression() do -:1659: { 3417:1660: if current.isTok:[comma]() do -:1661: { -:1662: var StackAppender:[64,Expression*] eapp; 138:1663: eapp.append(e); 138:1664: var auto te = (new TupleExpression).create(e.startPos, []); 138:1665: while true do -:1666: { 161:1667: advance(); 322:1668: if var auto ee = parseExpression() do 160:1669: eapp.append(ee); 1:1670: else do return freeAndNull(te); 160:1671: if current.isTok:[comma]() do 23:1672: continue; 137:1673: if current.isTok:[rightParen]() do -:1674: { 136:1675: advance(); 136:1676: te.expressions = eapp.reclaim(); 136:1677: return te; -:1678: } 1:1679: return freeAndNull(te); -:1680: } -:1681: } 3279:1682: if !current.isTok:[rightParen]() do 10:1683: return expected(rightParen, e); 3269:1684: e.parens++; 3269:1685: advance(); 3269:1686: return e; -:1687: } 12:1688: return null; -:1689: } -:1690: on intLiteral, binLiteral, hexLiteral do -:1691: { 12299:1692: advance(); 12299:1693: return (new IntegerExpression).create(p, curTok); -:1694: } -:1695: on floatLiteral do -:1696: { 125:1697: advance(); 125:1698: return (new FloatExpression).create(p, curTok); -:1699: } -:1700: on stringLiteral, rawStringLiteral do -:1701: { 4966:1702: advance(); 4966:1703: return (new StringExpression).create(p, curTok); -:1704: } -:1705: on $null do -:1706: { 1083:1707: advance(); 1083:1708: return (new NullExpression).create(p); -:1709: } -:1710: on $true, $false do -:1711: { 1803:1712: advance(); 1803:1713: return (new BoolExpression).create(p, curTok, curTok.isTok:[$true]()); -:1714: } -:1715: on leftSquare do -:1716: { 380:1717: return parseArrayExpression(); -:1718: } -:1719: on id do -:1720: { 51809:1721: advance(); 51809:1722: return (new IdentExpression).create(p, curTok); -:1723: } -:1724: on $bool .. $usize do -:1725: { 567:1726: var auto t = parseType(); 567:1727: return t ? (new TypeExpression).create(p, t) else error("invalid primary expression", null); -:1728: } -:1729: on $new, $delete do -:1730: { 1202:1731: const auto isNew = current.isTok:[$new](); 1202:1732: advance(); -:1733: var Expression* e0; -:1734: var Expression* e1; 1202:1735: if current.isTok:[leftParen]() do -:1736: { 28:1737: advance(); 28:1738: if (e0 = parseExpression()) == null do 3:1739: return null; 25:1740: if current.isTok:[comma]() do -:1741: { 17:1742: advance(); 17:1743: if (e1 = parseExpression()) == null do 2:1744: return freeAndNull(e0); -:1745: } 23:1746: if !current.isTok:[rightParen]() do -:1747: { 4:1748: freeAndNull(e0); 4:1749: freeAndNull(e1); 4:1750: return expected(TokenType.rightParen, null); -:1751: } 19:1752: advance(); -:1753: } 1174:1754: else do if (e0 = parseExpression()) == null do 1:1755: return null; 1192:1756: return isNew ? (new NewExpression).create(p, e0, e1) else (new DeleteExpression).create(p, e0, e1); -:1757: } 96:1758: else do return error("invalid primary expression", null); -:1759: } -:1760: } -:1761: -:1762: /// Returns: a `ProtectionDeclaration*` if one can be parsed otherwise `null` -:1763: function parseProtectionDeclaration(): ProtectionDeclaration* -:1764: { 176:1765: var auto result = (new ProtectionDeclaration).create(current.position); 176:1766: if !advance().isTok:[leftParen]() do 2:1767: return expected(TokenType.leftParen, result); 174:1768: if !advance().isTok:[id]() do 1:1769: return expected(TokenType.id, result); 173:1770: result.$protection = current; 173:1771: if !advance().isTok:[rightParen]() do 2:1772: return expected(TokenType.rightParen, result); 171:1773: advance(); 171:1774: return result; -:1775: } -:1776: -:1777: /// Returns: an `Expression*` if a `RShiftExpression` can be parsed otherwise `null` -:1778: function parseRShiftExpression(): Expression* -:1779: { 77054:1780: return parseBinaryExpression:[TokenType.rShift, RShiftExpression, echo(func), parseLShiftExpression](); -:1781: } -:1782: -:1783: /// Returns: a `ReturnStatement*` if one can be parsed otherwise `null` -:1784: function parseReturnStatement(): ReturnStatement* -:1785: { 4267:1786: var auto result = (new ReturnStatement).create(current.position); 4267:1787: if !advance().isTok:[semiColon]() do -:1788: { 7550:1789: if var auto e = parseExpression() do 3774:1790: result.expression = e; 1:1791: else do return freeAndNull(result); -:1792: } 4266:1793: if !current.isTok:[semiColon]() do 1:1794: return expected(TokenType.semiColon, result); 4265:1795: advance(); 4265:1796: result.stopPos = current.position; 4265:1797: return result; -:1798: } -:1799: -:1800: /// Returns: a `Statement*` if one can be parsed otherwise `null` -:1801: function parseStatement(): Statement* -:1802: { -:1803: var Statement* result; 28028:1804: switch current.type do -:1805: { 2068:1806: on $assert do return (result = parseAssertStatement(false)) ? result 5:1807: else error("invalid `assert` statement", null); 5427:1808: on $if do return (result = parseIfElseStatement()) ? result 24:1809: else error("invalid `if ... else` statement", null); 659:1810: on $foreach do return (result = parseForeachStatement()) ? result 23:1811: else error("invalid `foreach` statement", null); 15:1812: on $goto do return (result = parseBreakContinueOrGoto((new GotoStatement).create(current.position))) ? result 2:1813: else error("invalid `goto` statement", null); 4267:1814: on $return do return (result = parseReturnStatement()) ? result 2:1815: else error("invalid `return` statement", null); 346:1816: on $switch do return (result = parseSwitchStatement()) ? result 24:1817: else error("invalid `switch` statement", null); 37:1818: on $with do return (result = parseWithStatement()) ? result 9:1819: else error("invalid `with` statement", null); 516:1820: on $while do return (result = parseWhileStatement()) ? result 7:1821: else error("invalid `while` statement", null); 68:1822: on $leftCurly do return (result = parseBlockStatement()) ? result 1:1823: else error("invalid block statement", null); 56:1824: on $version do return (result = parseVersionBlockStatement()) ? result 12:1825: else error("invalid `version` statement", null); -:1826: on $break do -:1827: { 732:1828: if lookupNext().isTok:[$on]() do -:1829: { 11:1830: var auto bos = (new BreakOnStatement).create(current.position); 11:1831: advance(); 11:1832: advance(); 11:1833: bos.stopPos = current.position; 11:1834: if !current.isTok:[semiColon]() do 2:1835: return expected(TokenType.semiColon, bos); 9:1836: advance(); 9:1837: return bos; -:1838: } 721:1839: return (result = parseBreakContinueOrGoto((new BreakStatement).create(current.position))) ? result 1:1840: else error("invalid `break` statement", null); -:1841: } -:1842: on $continue do -:1843: { 303:1844: if lookupNext().isTok:[$on]() do -:1845: { 36:1846: return (result = parseContinueOnStatement()) ? result 3:1847: else error("invalid `continue on` statement", null); -:1848: } 267:1849: return (result = parseBreakContinueOrGoto((new ContinueStatement).create(current.position))) ? result 6:1850: else error("invalid `continue` statement", null); -:1851: } 13534:1852: else do return parseExpressionStatement(); -:1853: } -:1854: } -:1855: -:1856: /// Returns: a set of StorageClass -:1857: function parseStorageClasses(): StorageClasses -:1858: { -:1859: var StorageClasses result; 11606:1860: while true do -:1861: { 23438:1862: switch current.type do -:1863: { 4088:1864: on $const do result += StorageClass.$const ; 885:1865: on $static do result += StorageClass.$static ; 6859:1866: on $var do result += StorageClass.$var ; 11606:1867: else do return result; -:1868: } 11832:1869: advance(); -:1870: } -:1871: } -:1872: -:1873: /// Returns: an `AggregateDeclaration*` if a `StructDeclaration` can be parsed otherwise `null` -:1874: function parseStructDeclaration(): AggregateDeclaration* -:1875: { 457:1876: return parseAggregateDeclaration((new StructDeclaration).create(current.position)); -:1877: } -:1878: -:1879: /// Returns: an `Expression*` if a `SubExpression` can be parsed otherwise `null` -:1880: function parseSubExpression(): Expression* -:1881: { 78043:1882: return parseBinaryExpression:[TokenType.minus, SubExpression, echo(func), parseAddExpression](); -:1883: } -:1884: -:1885: /// Returns: a `SwitchStatement*` if one can be parsed otherwise `null` -:1886: function parseSwitchStatement(): SwitchStatement* -:1887: { 346:1888: var auto result = (new SwitchStatement).create(current.position); 346:1889: advance(); 346:1890: if (result.expression = parseExpression()) == null do 2:1891: return freeAndNull(result); 344:1892: if !current.isTok:[$do]() do 2:1893: return expected(TokenType.$do, result); 342:1894: if !advance().isTok:[leftCurly]() do 1:1895: return expected(TokenType.leftCurly, result); 341:1896: advance(); 341:1897: while true do -:1898: { 2039:1899: if current.isTok:[$on]() do -:1900: { 3414:1901: if var auto oms = parseOnMatchStatement() do 1698:1902: continue result.onMatchStatements ~= oms; 9:1903: return freeAndNull(result); -:1904: } 332:1905: if current.isTok:[$else]() || current.isTok:[rightCurly]() do 328:1906: break; 4:1907: return unexpected(result); -:1908: } 328:1909: if result.onMatchStatements.length == 0 do 1:1910: return error("expected at least one `on` match statement", result); 327:1911: if current.isTok:[$else]() do -:1912: { 278:1913: if !advance().isTok:[$do]() do 2:1914: return expected(TokenType.$do, result); 276:1915: advance(); 276:1916: if (result.elseBlock = parseBlockStatement()) == null do 2:1917: return freeAndNull(result); -:1918: } 323:1919: if !current.isTok:[rightCurly]() do 1:1920: return expected(TokenType.rightCurly, result); 322:1921: advance(); 322:1922: return result; -:1923: } -:1924: -:1925: /// Returns: a `Type*` if one can be parsed otherwise `null` -:1926: function parseType(): Type* -:1927: { 21712:1928: if current.isTok:[$auto]() do -:1929: { 3075:1930: advance(); 3075:1931: return TypeAuto.instance(); -:1932: } 18637:1933: if current.isTok:[leftParen]() && lookupNext().isTok:[rightParen]() do -:1934: { 10:1935: advance(); 10:1936: advance(); 10:1937: return TypeVoid.instance(); -:1938: } -:1939: 18627:1940: var auto p = current.position; -:1941: var Type* result; -:1942: 18627:1943: switch current.type do -:1944: { 90:1945: on leftParen do { result = parseUnambiguousType(); } 1598:1946: on $bool do { result = TypeBool.instance(); advance(); } 4766:1947: on $u8 do { result = TypeU8.instance(); advance(); } 610:1948: on $u16 do { result = TypeU16.instance(); advance(); } 2308:1949: on $u32 do { result = TypeU32.instance(); advance(); } 1210:1950: on $u64 do { result = TypeU64.instance(); advance(); } 3464:1951: on $usize do { result = TypeUSize(); advance(); } 4688:1952: on $s8 do { result = TypeS8.instance(); advance(); } 154:1953: on $s16 do { result = TypeS16.instance(); advance(); } 5006:1954: on $s32 do { result = TypeS32.instance(); advance(); } 340:1955: on $s64 do { result = TypeS64.instance(); advance(); } 416:1956: on $ssize do { result = TypeSSize(); advance(); } 62:1957: on $f32 do { result = TypeF32.instance(); advance(); } 164:1958: on $f64 do { result = TypeF64.instance(); advance(); } -:1959: on $echo do -:1960: { 44:1961: if var auto e = parsePrimaryExpression() do 21:1962: result = (new TypeEcho).create(e); 1:1963: else do return freeAndNull(result); -:1964: } -:1965: on $static, $function do -:1966: { -:1967: var StorageClasses stc; 109:1968: if current.isTok:[$static]() do 33:1969: stc = parseStorageClasses(); 218:1970: if var auto fd = parseFunctionDeclaration(true) do -:1971: { 102:1972: if fd.isVar() do 1:1973: stc += StorageClass.$var; 102:1974: fd.stc = stc; 102:1975: result = (new TypeFunction).create(fd, true); -:1976: } 7:1977: else do return error("invalid function type", result); -:1978: } 5993:1979: on id do result = parseTypeIdentifier(); 20:1980: else do {} -:1981: } 18619:1982: if !result do 30:1983: return error("invalid type", null); 18589:1984: return parseTypeModified(p, result); -:1985: } -:1986: -:1987: /// Returns: a `Type*` if one can be parsed otherwise `null` -:1988: function parseTypeModified(var Position p; Type* result): Type* -:1989: { 18591:1990: while true do -:1991: { 28675:1992: if current.isTok:[mul]() do -:1993: { 7997:1994: result = (new TypePointer).create(result); 7997:1995: advance(); 7997:1996: continue; -:1997: } 20678:1998: else do if current.isTok:[leftSquare]() do -:1999: { 2107:2000: switch lookupNext().type do -:2001: { -:2002: on TokenType.rightSquare do -:2003: { 1796:2004: advance(); advance(); 898:2005: continue result = (new TypeSlice).create(result); -:2006: } -:2007: on TokenType.plus do -:2008: { 1772:2009: advance(); advance(); 886:2010: if current.isTok:[rightSquare]() do -:2011: { 885:2012: result = (new TypeRcArray).create(result); 885:2013: continue advance(); -:2014: } 1:2015: return expected(TokenType.rightSquare, result); -:2016: } -:2017: else do -:2018: { 323:2019: advance(); 646:2020: if var auto e = parseExpression() do -:2021: { 320:2022: switch current.type do -:2023: { -:2024: on TokenType.rightSquare do -:2025: { 304:2026: result = (new TypeStaticArray).create(result, e); 304:2027: continue advance(); -:2028: } -:2029: on TokenType.comma do -:2030: { 14:2031: var auto te = (new TypeElements).create(result, [e]); 14:2032: while true do -:2033: { 16:2034: advance(); 32:2035: if var auto ee = parseExpression() do 15:2036: te.indexes ~= ee; 1:2037: else do return freeAndNull(te); 15:2038: if current.isTok:[comma]() do 2:2039: continue; 13:2040: if current.isTok:[rightSquare]() do -:2041: { 11:2042: advance(); 11:2043: return te; -:2044: } 2:2045: return freeAndNull(te); -:2046: } -:2047: } 2:2048: else do return freeAndNull(e); -:2049: } -:2050: } 3:2051: return freeAndNull(result); -:2052: } -:2053: } -:2054: } -:2055: else do -:2056: { 18571:2057: result.startPos = p; 18571:2058: return result; -:2059: } -:2060: } -:2061: } -:2062: -:2063: /// Returns: a `TypeIdentifier*` if one can be parsed otherwise `null` -:2064: function parseTypeIdentifier(bool allowGenericApp = true): TypeIdentifier* -:2065: { -:2066: var TypeIdentifier* tidPrev; -:2067: var TypeIdentifier* result; 7617:2068: while true do -:2069: { 8282:2070: if !current.isTok:[id]() do 11:2071: return expected(TokenType.id, result); 8271:2072: var auto tidNext = (new TypeIdentifier).create(current); 8271:2073: tidNext.startPos = current.position; 8271:2074: result ?= tidNext; 8271:2075: if tidPrev do 663:2076: tidPrev.next = tidNext; 8271:2077: advance(); 8271:2078: if current.isTok:[colon]() && lookupNext().isTok:[leftSquare]() do -:2079: { 62:2080: if !allowGenericApp do 2:2081: return unexpected(result); 60:2082: advance(); 60:2083: advance(); -:2084: var StackAppender:[64,Expression*] eapp; 60:2085: while true do -:2086: { 87:2087: var auto e = parseExpression(); 87:2088: if !e do 3:2089: return freeAndNull(result); 84:2090: eapp.append(e); 84:2091: if current.isTok:[comma]() do 27:2092: continue advance(); 57:2093: if current.isTok:[rightSquare]() do 55:2094: break advance(); 2:2095: return unexpected(result); -:2096: } 55:2097: tidNext.genericArguments = eapp.reclaim(); -:2098: } 8264:2099: tidPrev = tidNext; 8264:2100: if !current.isTok:[dot]() do 7599:2101: break; 665:2102: advance(); -:2103: } 7599:2104: return result; -:2105: } -:2106: -:2107: /// Returns: a `Type*` if a `TypeUnambiguous` can be parsed otherwise `null` -:2108: function parseUnambiguousType(): Type* -:2109: { 90:2110: advance(); 90:2111: var auto result = parseType(); 90:2112: if !result do 1:2113: return null; 89:2114: if current.isTok:[comma]() do -:2115: { 54:2116: var auto tt = (new TypeTuple).create([result]); 54:2117: while true do -:2118: { 73:2119: advance(); 146:2120: if var auto t = parseType() do 72:2121: tt.types ~= t; 1:2122: else do return freeAndNull(tt); 72:2123: if current.isTok:[comma]() do 19:2124: continue; 53:2125: if current.isTok:[rightParen]() do -:2126: { 52:2127: advance(); 52:2128: return tt; -:2129: } 1:2130: return freeAndNull(tt); -:2131: } -:2132: } 35:2133: if !current.isTok:[rightParen]() do 1:2134: return expected(TokenType.rightParen, result); 34:2135: advance(); 34:2136: return isTypeAuto(result) || isTypeVoid(result) ? null else (new TypeUnambiguous).create(result); -:2137: } -:2138: -:2139: /// Returns: an `AggregateDeclaration*` if a `UnionDeclaration` can be parsed otherwise `null` -:2140: function parseUnionDeclaration(): AggregateDeclaration* -:2141: { 35:2142: return parseAggregateDeclaration((new UnionDeclaration).create(current.position)); -:2143: } -:2144: -:2145: /// Returns: an `Expression*` if an `UnaryExpression` can be parsed otherwise `null` -:2146: function parseUnaryExpression(): Expression* -:2147: { 83612:2148: var auto p = current.position; 83612:2149: switch current.type do -:2150: { -:2151: // PreExpressions 648:2152: on plusPlus do { advance(); if var auto u = parseUnaryExpression() do return (new PreIncExpression).create(p, u); } 440:2153: on minMin do { advance(); if var auto u = parseUnaryExpression() do return (new PreDecExpression).create(p, u); } 5496:2154: on mul do { advance(); if var auto u = parseUnaryExpression() do return (new DerefExpression).create(p, u); } 1712:2155: on amp do { advance(); if var auto u = parseUnaryExpression() do return (new AtExpression).create(p, u); } 5432:2156: on not do { advance(); if var auto u = parseUnaryExpression() do return (new NotExpression).create(p, u); } 79:2157: on tidle do { advance(); if var auto u = parseUnaryExpression() do return (new OneCompExpression).create(p, u); } 1128:2158: on minus do { advance(); if var auto u = parseUnaryExpression() do return (new NegExpression).create(p, u); } -:2159: // PostExpressions 159754:2160: else do if var auto pe = parsePrimaryExpression() do -:2161: { 79712:2162: var auto toPostFix = pe; -:2163: 79712:2164: while true do -:2165: { 117569:2166: p = current.position; 117569:2167: switch current.type do -:2168: { 968:2169: on plusPlus do {toPostFix = (new PostIncExpression).create(p, toPostFix); advance(); } 166:2170: on minMin do {toPostFix = (new PostDecExpression).create(p, toPostFix); advance(); } 2403:2171: on leftSquare do toPostFix = parseIndexOrSliceExpression(p, toPostFix); 13627:2172: on leftParen do toPostFix = parseCallExpression(p, toPostFix); -:2173: on colon do -:2174: { 2861:2175: advance(); 2861:2176: if current.isTok:[leftSquare]() do -:2177: { 526:2178: advance(); -:2179: var StackAppender:[64,Expression*] eapp; 526:2180: while true do -:2181: { 620:2182: var auto e = parseExpression(); 620:2183: if !e do 4:2184: return freeAndNull(toPostFix); 616:2185: eapp.append(e); 616:2186: if current.isTok:[comma]() do 94:2187: continue advance(); 522:2188: if current.isTok:[rightSquare]() do 521:2189: break advance(); 1:2190: return unexpected(toPostFix); -:2191: } 521:2192: toPostFix = (new ApplyExpression).create(p, toPostFix, eapp.reclaim(), true); -:2193: } 4670:2194: else do if var auto t = parseType() do 2332:2195: toPostFix = (new CastExpression).create(p, toPostFix, t); 3:2196: else do return freeAndNull(toPostFix); -:2197: } -:2198: on dot do -:2199: { 18208:2200: advance(); 18208:2201: if current.isTok:[id]() do -:2202: { 18205:2203: toPostFix = (new DotExpression).create(p, toPostFix, (new IdentExpression).create(current.position, current)); 18205:2204: advance(); -:2205: } 3:2206: else do return freeAndNull(toPostFix); -:2207: } -:2208: on qmark do -:2209: { 777:2210: if lookupNext().isTok:[dot]() do -:2211: { 171:2212: advance(); 171:2213: toPostFix = (new OptAccessExpression).create(current.position, toPostFix); -:2214: } -:2215: // take the path of ConditionalExpression 606:2216: else do return toPostFix; -:2217: } -:2218: on mul do -:2219: { 474:2220: const auto t = lookupNext().type; 474:2221: switch t do -:2222: { -:2223: // Still a TypeModified, e.g: `T**` `T*[]`, or a DotExp, e.g `A*.sizeof` -:2224: on mul, leftSquare, dot do -:2225: { 31:2226: toPostFix = (new MulExpression).create(current.position, toPostFix, null); 31:2227: advance(); -:2228: } -:2229: // Tried as TypeExp, e.g: `generic:[A*]` `generic:[A*, A]` -:2230: on rightSquare, comma, rightParen do -:2231: { 24:2232: toPostFix = (new MulExpression).create(current.position, toPostFix, null); 24:2233: advance(); 24:2234: return toPostFix; -:2235: } -:2236: // regular MulExp 419:2237: else do return toPostFix; -:2238: } -:2239: } 78652:2240: else do return toPostFix; -:2241: } -:2242: } -:2243: } -:2244: } 170:2245: return null; -:2246: } -:2247: -:2248: /// Returns: a `UnitDeclaration*` if one can be parsed otherwise `null` -:2249: function parseUnitDeclaration(): UnitDeclaration* -:2250: { 1198:2251: current = lexer.front(); 1198:2252: const auto needAttribs = current.isTok:[at](); 1198:2253: var auto attribs = needAttribs ? parseAttributes() else null; 1198:2254: if needAttribs && !attribs do 2:2255: return null; 1196:2256: if !current.isTok:[TokenType.$unit]() do 1:2257: return expected(TokenType.$unit, attribs); 1195:2258: var auto result = (new UnitDeclaration).create(current.position, attribs, lexer.filename()[]); 1195:2259: result.isHeader = isHeader; 1195:2260: if !advance().isTok:[id]() do 3:2261: return expected(TokenType.id, result); 2384:2262: if var auto t = parseTypeIdentifier(false) do -:2263: { 1191:2264: result.identifiers = t; 1191:2265: if !current.isTok:[semiColon]() do 3:2266: return expected(TokenType.semiColon, result); 1188:2267: advance(); 2376:2268: if var auto d = parseDeclarations() do -:2269: { 820:2270: result.declarations = d; 820:2271: if current.isTok:[eof]() do -:2272: { 820:2273: result.stopPos = current.position; 820:2274: $unit = result; 820:2275: return result; -:2276: } -:2277: } -:2278: } 369:2279: return freeAndNull(result); -:2280: } -:2281: -:2282: /// Returns: a `VariableDeclaration*` if one can be parsed otherwise `null` -:2283: function parseVariableDeclaration(bool needSemicolon; bool allowThis = false): VariableDeclaration* -:2284: { 14861:2285: var auto result = (new VariableDeclaration).create(current.position); 14861:2286: var auto t = parseType(); 14861:2287: if !t do 28:2288: return freeAndNull(result); 14833:2289: result.type = t; 14833:2290: if allowThis && current.isTok:[TokenType.$this]() do 15:2291: result.name = thisToken(); -:2292: else do -:2293: { 14818:2294: if !current.isTok:[id]() do 13:2295: return error("expected identifier", result); 14805:2296: result.name = current; -:2297: } 14820:2298: if advance().isTok:[ass]() do -:2299: { 5340:2300: advance(); 10680:2301: if var auto e = parseExpression() do 5306:2302: result.initializer = e; 34:2303: else do return freeAndNull(result); -:2304: } 14786:2305: if !needSemicolon do 7217:2306: return result; 7569:2307: if !current.isTok:[semiColon]() do 8:2308: return expected(TokenType.semiColon, result); 7561:2309: advance(); 7561:2310: return result; -:2311: } -:2312: -:2313: /// Returns: a `Expression*` if a `VersionAndAndExpression` can be parsed otherwise `null` -:2314: function parseVersionAndAndExpression(): Expression* -:2315: { 294:2316: return parseBinaryExpression:[TokenType.andAnd, AndAndExpression, echo(func), parseVersionPrimaryExpression](); -:2317: } -:2318: -:2319: /// Returns: a `VersionBlockDeclaration*` if one can be parsed otherwise `null` -:2320: function parseVersionBlockDeclaration(): VersionBlockDeclaration* -:2321: { 117:2322: advance(); 117:2323: var auto result = (new VersionBlockDeclaration).create(current.position); 234:2324: if var auto voe = parseVersionOrOrExpression() do -:2325: { 111:2326: voe.type = TypeBool.instance(); 111:2327: result.versionExpression = voe; -:2328: } 6:2329: else do return error("invalid `version` expression", result); 111:2330: if !current.isTok:[$do]() do 1:2331: return expected(TokenType.$do, result); 110:2332: if advance().isTok:[leftCurly]() do -:2333: { 68:2334: advance(); 136:2335: if var auto ds = parseDeclarations() do -:2336: { 67:2337: result.thenDeclarations = ds; 67:2338: advance(); -:2339: } 1:2340: else do return freeAndNull(result); -:2341: } -:2342: else do -:2343: { 84:2344: if var auto d = parseDeclaration() do 41:2345: result.thenDeclarations = (new Declarations).create(d.startPos, [d]); 1:2346: else do return freeAndNull(result); -:2347: } 108:2348: if current.isTok:[$else]() do -:2349: { 63:2350: if !advance().isTok:[$do]() do 1:2351: return expected(TokenType.$do, result); 62:2352: if advance().isTok:[leftCurly]() do -:2353: { 7:2354: advance(); 14:2355: if var auto ds = parseDeclarations() do -:2356: { 6:2357: result.elseDeclarations = ds; 6:2358: advance(); -:2359: } 1:2360: else do return freeAndNull(result); -:2361: } -:2362: else do -:2363: { 110:2364: if var auto d = parseDeclaration() do 54:2365: result.elseDeclarations = (new Declarations).create(d.startPos, [d]); 1:2366: else do return freeAndNull(result); -:2367: } -:2368: } 105:2369: return result; -:2370: } -:2371: -:2372: /// Returns: a `VersionBlockStatement*` if one can be parsed otherwise `null` -:2373: function parseVersionBlockStatement(): VersionBlockStatement* -:2374: { 56:2375: advance(); 56:2376: var auto result = (new VersionBlockStatement).create(current.position); 112:2377: if var auto voe = parseVersionOrOrExpression() do -:2378: { 51:2379: voe.type = TypeBool.instance(); 51:2380: result.versionExpression = voe; -:2381: } 5:2382: else do return error("invalid `version` expression", result); 51:2383: if !current.isTok:[$do]() do 2:2384: return expected(TokenType.$do, result); 49:2385: advance(); 51:2386: if (result.thenBlock = parseBlockStatement()) == null do return freeAndNull(result); 47:2387: result.thenBlock.noScope = true; 47:2388: if current.isTok:[$else]() do -:2389: { 22:2390: if !advance().isTok:[$do]() do 1:2391: return expected(TokenType.$do, result); 21:2392: advance(); 23:2393: if (result.elseBlock = parseBlockStatement()) == null do return freeAndNull(result); 19:2394: result.elseBlock.noScope = true; -:2395: } 44:2396: return result; -:2397: } -:2398: -:2399: /// Returns: a `Expression*` if a `VersionOrOrExpression` can be parsed otherwise `null` -:2400: function parseVersionOrOrExpression(): Expression* -:2401: { 258:2402: return parseBinaryExpression:[TokenType.orOr, OrOrExpression, echo(func), parseVersionAndAndExpression](); -:2403: } -:2404: -:2405: /// Returns: a `VersionPrimaryExpression*` if one can be parsed otherwise `null` -:2406: function parseVersionPrimaryExpression(): Expression* -:2407: { -:2408: var Expression* result; 299:2409: switch current.type do -:2410: { -:2411: on not do -:2412: { 5:2413: var auto pe = (new NotExpression).create(current.position); 5:2414: result = pe; 5:2415: advance(); 10:2416: if var auto e = parseVersionPrimaryExpression() do -:2417: { 5:2418: e.type = TypeBool.instance(); 5:2419: pe.type = TypeBool.instance(); 5:2420: pe.expression = e; 5:2421: return pe; -:2422: } -:2423: } -:2424: on leftParen do -:2425: { 67:2426: advance(); 134:2427: if var auto e = parseVersionOrOrExpression() do -:2428: { 63:2429: result = e; 63:2430: e.type = TypeBool.instance(); 63:2431: if current.isTok:[rightParen]() do -:2432: { 57:2433: advance(); 57:2434: e.parens++; 57:2435: e.type = TypeBool.instance(); 57:2436: return e; -:2437: } -:2438: } -:2439: } -:2440: on id do -:2441: { -:2442: var auto vie = (new VersionIdentExpression) 213:2443: .create(current.position, current, TypeBool.instance()); 213:2444: advance(); 213:2445: return vie; -:2446: } 14:2447: else do {/*error*/} -:2448: } 24:2449: return unexpected(result); -:2450: } -:2451: -:2452: /// Returns: a `WhileStatement*` if one can be parsed otherwise `null` -:2453: function parseWhileStatement(): WhileStatement* -:2454: { 516:2455: var auto result = (new WhileStatement).create(current.position); 516:2456: advance(); 516:2457: result.condition = parseExpression(); 516:2458: if !current.isTok:[$do]() do 5:2459: return expected(TokenType.$do, result); 511:2460: advance(); 511:2461: return (result.blockStatement = parseBlockStatement()) ? result else freeAndNull(result); -:2462: } -:2463: -:2464: /// Returns: a `WithStatement*` if one can be parsed otherwise `null` -:2465: function parseWithStatement(): WithStatement* -:2466: { 37:2467: var auto result = (new WithStatement).create(current.position); 37:2468: advance(); 37:2469: const auto needRightParen = current.isTok:[leftParen](); 37:2470: if needRightParen do 17:2471: advance(); 37:2472: while true do -:2473: { 94:2474: if var auto e = parseExpression() do 43:2475: result.expressions ~= e; 4:2476: else do return freeAndNull(result); 43:2477: if current.isTok:[comma]() do 10:2478: continue advance(); 33:2479: if current.isTok:[rightParen]() && needRightParen do 12:2480: break advance(); 21:2481: if current.isTok:[$do]() && !needRightParen do 18:2482: break; 3:2483: return unexpected(result); -:2484: } 30:2485: if !current.isTok:[$do]() do 1:2486: return expected(TokenType.$do, result); 29:2487: advance(); 29:2488: return (result.blockStatement = parseBlockStatement()) ? result else freeAndNull(result); -:2489: } -:2490: -:2491: /// Returns: an `Expression*` if a `XorExpression` can be parsed otherwise `null` -:2492: function parseXorExpression(): Expression* -:2493: { 72479:2494: return parseBinaryExpression:[TokenType.xor, XorExpression, echo(func), parseAndExpression](); -:2495: } -:2496:} -:2497: -:2498:/// Asserts that `code` starting at `line` can be parsed or not, depending on `mustParse` -:2499:function assertParseOrNot(s8[] code; u32 line; bool mustParse) -:2500:{ 571:2501: var auto lx = (new Lexer).createFromText(code, echo(filename), line, 0); 571:2502: var auto p = (new Parser).create(lx, false); 571:2503: const auto ec = session.errorsCount(); 571:2504: p.parseUnitDeclaration(); 571:2505: p.getUnit(); 571:2506: if (ec != session.errorsCount()) && mustParse do -:2507: { 0:2508: session.error(echo(filename), (line, 0), "unittest failure, code not parsed but should be"); 0:2509: system.fflush(0); 0:2510: asm ("ud2"); -:2511: } 571:2512: else do if (ec == session.errorsCount()) && !mustParse do -:2513: { 0:2514: session.error(echo(filename), (line, 0), "unittest failure, code parsed but should not be"); 0:2515: system.fflush(0); 0:2516: asm ("ud2"); -:2517: } 571:2518: delete p; 571:2519: delete lx; 571:2520:} -:2521: -:2522:/// Asserts that `code` starting at `line` can be parsed -:2523:function assertParse(s8[] code; u64 line) -:2524:{ 179:2525: assertParseOrNot(code, line:u32, true); 179:2526:} -:2527: -:2528:/// Asserts that `code` starting at `line` cannot be parsed -:2529:function assertNotParse(s8[] code; u64 line) -:2530:{ 392:2531: assertParseOrNot(code, line:u32, false); 392:2532:} -:2533: -:2534:@unittest function test1() -:2535:{ -:2536: const u64 line = echo(line) + 1; -:2537: `unit u; -:2538: @abstract class C {} -:2539: @@user struct S {} -:2540: union U {} -:2541: enum E {e0, e1} -:2542: var s32** a; -:2543: @noopt @@B function f(){{ break; continue; }} -:2544: alias F = function();`.assertParse(line); -:2545:} -:2546: -:2547:@unittest function test2() -:2548:{ -:2549: const u64 line = echo(line) + 2; -:2550: `unit u; -:2551: class C {} -:2552: struct S {} -:2553: union U {} -:2554: var s32 a; -:2555: alias F = function(++++`.assertNotParse(line); -:2556:} -:2557: -:2558:@unittest function test3() -:2559:{ -:2560: `unit u; version a && !b || c do {} else do {}`.assertParse(echo(line)); -:2561: `unit u; function main(): s32 { return ~~~(0+0/g?.t[1].call())%100++--++--:u64*; }`.assertParse(echo(line)); -:2562:} -:2563: -:2564:@unittest function test4() -:2565:{ -:2566: const auto line = echo(line) + 2; -:2567: assertParse(` -:2568: unit a; -:2569: var s32 a; -:2570: var s32* a; -:2571: var s32***** a; -:2572: var s32*****[][]**[] a; -:2573: var s32[1][2+5]**[] a; -:2574: var F f; -:2575: var F.A.D.E**[] f; -:2576: var F.A.D.E**[+] f; -:2577: var () f; -:2578: var u8 f; var u16 f; var u32 f; var u64 f; -:2579: var s8 f; var s16 f; var s32 f; var s64 f; -:2580: var u64[+] a; -:2581: var f64[+] a; -:2582: var ssize[+] a; -:2583: var usize[+] a; -:2584: `, line); -:2585:} -:2586: -:2587:@unittest function test5() -:2588:{ -:2589: assertParse(`unit a.b.c.d.e.f.g;`, echo(line)); -:2590: assertNotParse(`unit`, echo(line)); -:2591: assertNotParse(`unit ;`, echo(line)); -:2592: assertNotParse(`unit a; unit b;`, echo(line)); -:2593: assertParse(`@inline unit u;`, echo(line)); -:2594: assertParse(`@inline @inline unit u;`, echo(line)); -:2595: assertNotParse(`@inline @( unit u;`, echo(line)); -:2596: assertParse(`@@user unit u;`, echo(line)); -:2597: assertNotParse(`@cosnstructor unit u;`, echo(line)); -:2598: assertNotParse(`unit u; struct Foo struct Foo {class Foo {struct Foo {}}} `, echo(line)); -:2599: assertNotParse(`unit struct.class.function;`, echo(line)); -:2600: assertParse(`unit $struct.$class.$function;`, echo(line)); -:2601:} -:2602: -:2603:@unittest function test6() -:2604:{ -:2605: const auto line = echo(line) + 1; -:2606: assertParse(` -:2607: unit a.b; -:2608: function bar(const u32 a; var u64 d); -:2609: function bar(u32 a; var u64 d){} -:2610: function bar(u32 a; u64 d): u64; -:2611: function bar(u32 a; u64 d): u64 {} -:2612: function bar(function _(u32 a) callback): function _(); -:2613: var function _(const u32 a; u64 d) a; -:2614: @override var function _(u32 a; var u64 d) a; -:2615: var function _(u32 a; u64 d): u64 a; -:2616: var function _(u32 a; u64 d): u64 a; -:2617: var function _(function _(u32 a) callback): function _() a; -:2618: function bar(@@foo const u32 a; @@bar u64 d){ a ? b else c*g; } -:2619: `, line); -:2620:} -:2621: -:2622:@unittest function test7() -:2623:{ -:2624: assertNotParse(` -:2625: unit a; -:2626: function foo() :(Ambiguous -:2627: { -:2628: } -:2629: `,0); -:2630: assertNotParse(` -:2631: unit a; -:2632: function foo() -:2633: { -:2634: a(a a -:2635: } -:2636: `,0); -:2637: assertNotParse(` -:2638: unit a -:2639: `,0); -:2640: assertNotParse(` -:2641: unit a; -:2642: function foo() -:2643: { -:2644: a@ -:2645: } -:2646: `,0); -:2647: assertNotParse(` -:2648: unit a; -:2649: function foo() -:2650: { -:2651: a:= -:2652: } -:2653: `,0); -:2654: assertNotParse(` -:2655: unit a; -:2656: function foo() -:2657: { -:2658: a(exp] -:2659: } -:2660: `,0); -:2661: assertParse(` -:2662: unit a; -:2663: function foo() -:2664: { -:2665: a = b?.c?.d; -:2666: } -:2667: `,0); -:2668: assertNotParse(` -:2669: unit a; -:2670: function foo() -:2671: { -:2672: a = b??.c?.d; -:2673: } -:2674: `,0); -:2675: assertNotParse(` -:2676: unit a; -:2677: function foo() -:2678: { -:2679: a = .b..c?.d; -:2680: } -:2681: `,0); -:2682: assertNotParse(` -:2683: unit a; -:2684: function foo() -:2685: { -:2686: (a+a; -:2687: } -:2688: `,0); -:2689: assertNotParse(` -:2690: unit a; -:2691: function foo() -:2692: { -:2693: (] -:2694: } -:2695: `,0); -:2696: assertNotParse(` -:2697: unit a; -:2698: function foo() -:2699: { -:2700: ++++; -:2701: } -:2702: `,0); -:2703: assertNotParse(` -:2704: unit a; -:2705: function foo() -:2706: { -:2707: a = s32[0; -:2708: } -:2709: `,0); -:2710: assertNotParse(` -:2711: unit a; -:2712: function foo() -:2713: { -:2714: ++a.a.] -:2715: } -:2716: `,0); -:2717: assertNotParse(` -:2718: unit a; -:2719: function foo() -:2720: { -:2721: (a).] -:2722: } -:2723: `,0); -:2724: assertNotParse(` -:2725: unit a; -:2726: function foo() -:2727: { -:2728: (a).....(a); -:2729: } -:2730: `,0); -:2731: assertParse(` -:2732: unit a; -:2733: function foo() -:2734: { -:2735: a = "stringLiteral"; -:2736: } -:2737: `,0); -:2738: assertParse(` -:2739: unit a; -:2740: function foo() -:2741: { -:2742: call("stringLiteral"); -:2743: } -:2744: `,0); -:2745: assertNotParse(` -:2746: unit a; -:2747: function foo() -:2748: { -:2749: call(#); -:2750: } -:2751: `,0); -:2752: assertParse(` -:2753: unit a; -:2754: function foo() -:2755: { -:2756: if (a < 8) do {} -:2757: } -:2758: `,0); -:2759: assertParse(` -:2760: unit u; -:2761: const f32 a = 0.1; -:2762: `,0); -:2763: assertParse(` -:2764: unit u; -:2765: function foo(){ a = b = 0; } -:2766: `,0); -:2767: assertParse(` -:2768: unit u; -:2769: function foo(@@a @@b @@c f32 p); -:2770: `,0); -:2771: assertNotParse(` -:2772: unit u; -:2773: function t1(ng){} -:2774: function t2(s8 ok; ng){} -:2775: `,0); -:2776: assertParse(` -:2777: unit u; -:2778: function foo(){this.a.b = 0;} -:2779: `,0); -:2780: assertParse(` -:2781: unit u; -:2782: /* -:2783: */ -:2784: //function foo -:2785: `,0); -:2786: assertParse(` -:2787: unit u; -:2788: function fun() -:2789: { -:2790: -b; -:2791: *b; -:2792: &b; -:2793: !b; -:2794: } -:2795: `,0); -:2796: assertNotParse(` -:2797: unit a; -:2798: function foo() -:2799: { -:2800: return 0 -:2801: } -:2802: `,0); -:2803: assertParse(` -:2804: unit a; -:2805: @virtual function A.foo() -:2806: { -:2807: } -:2808: `,0); -:2809:} -:2810: -:2811:@unittest function test8() -:2812:{ -:2813: assertNotParse(` -:2814: unit u; -:2815: function main(): s32 -:2816: { -:2817: var s32 b = S.f().a -:2818: return b; -:2819: } -:2820: `,0); -:2821: assertNotParse(` -:2822: unit u; -:2823: function main() -:2824: { -:2825: (8 + 3)3; -:2826: } -:2827: `,0); -:2828: assertParse(` -:2829: unit u; -:2830: var s32[+] a; -:2831: `,0); -:2832: assertNotParse(` -:2833: unit u; -:2834: var s32[+ a; -:2835: `,0); -:2836: assertNotParse(` -:2837: unit u; -:2838: alias b = (s32) auto; -:2839: `,0); -:2840: assertNotParse(` -:2841: unit u; -:2842: function f(){ @danglingAttrib expStatement; } -:2843: `,0); -:2844: assertParse(` -:2845: unit u; -:2846: var auto a = [0..1..2]; -:2847: `,0); -:2848: assertNotParse(` -:2849: unit u; -:2850: var auto a = [0..1..]; -:2851: `,0); -:2852: assertParse(` -:2853: unit u; -:2854: var auto a = b[0..$]; -:2855: `,0); -:2856: assertNotParse(` -:2857: unit u; -:2858: function f() -:2859: { -:2860: switch e do -:2861: { -:2862: on a do {} -:2863: else do { -:2864: `,0); -:2865: assertNotParse(` -:2866: unit u; -:2867: function test() -:2868: { -:2869: if rand() do {} -:2870: var sdf -:2871: if rand() do {} -:2872: } -:2873: `,0); -:2874: assertNotParse(` -:2875: unit u; -:2876: function test() -:2877: { -:2878: var -:2879: if rand() do {} -:2880: }`,0); -:2881: assertParse(` -:2882: unit u; -:2883: var auto a = b?=b+=b-=b/=b*=b&=b|=b^=b<<=b>>=b%=b; -:2884: `,0); -:2885:} -:2886: -:2887:@unittest function testFuncDecl() -:2888:{ -:2889: assertNotParse(` -:2890: unit a; -:2891: function foo(; -:2892: `,0); -:2893: assertParse(` -:2894: unit a; -:2895: static function foo(); -:2896: `,0); -:2897: assertNotParse(` -:2898: unit a; -:2899: function foo; -:2900: `,0); -:2901: assertNotParse(` -:2902: unit a; -:2903: function foo; -:2904: `,0); -:2905: assertNotParse(` -:2906: unit a; -:2907: function foo(; -:2908: `,0); -:2909: assertNotParse(` -:2910: unit a; -:2911: function foo():; -:2912: `,0); -:2913: assertNotParse(` -:2914: unit a; -:2915: function ():; -:2916: `,0); -:2917: assertNotParse(` -:2918: unit a; -:2919: function a(): a k -:2920: `,0); -:2921: assertNotParse(` -:2922: unit a; -:2923: function a(){; -:2924: `,0); -:2925: assertNotParse(` -:2926: unit a; -:2927: var function _foo(; -:2928: `,0); -:2929: assertNotParse(` -:2930: unit a; -:2931: var function foo; -:2932: `,0); -:2933: assertNotParse(` -:2934: unit a; -:2935: var function* foo; -:2936: `,0); -:2937: assertNotParse(` -:2938: unit a; -:2939: var function foo; -:2940: `,0); -:2941: assertNotParse(` -:2942: unit a; -:2943: var function _(; -:2944: `,0); -:2945: assertNotParse(` -:2946: unit a; -:2947: var function _():; -:2948: `,0); -:2949: assertNotParse(` -:2950: unit a; -:2951: function foo(): static -:2952: `,0); -:2953: assertParse(` -:2954: unit a; -:2955: function foo(const const s32 a); -:2956: `,0); -:2957: assertParse(` -:2958: unit a; -:2959: function foo(var var s32 a); -:2960: `,0); -:2961: assertParse(` -:2962: unit a; -:2963: function foo(var s32 p1; const s8 p2); -:2964: `,0); -:2965: assertParse(` -:2966: unit a; -:2967: function foo(var const var const s32 a); -:2968: `,0); -:2969: assertNotParse(` -:2970: unit a; -:2971: function foo(var const var s32 a,,); -:2972: `,0); -:2973: assertParse(` -:2974: unit a; -:2975: function foo(var const var s32 a; const C c; const D d;); -:2976: `,0); -:2977: assertParse(` -:2978: unit a; -:2979: function foo(var const var s32 a; const C c; const D d); -:2980: `,0); -:2981: assertParse(` -:2982: unit a; -:2983: @virtual function foo(){} -:2984: `,0); -:2985: assertParse(` -:2986: unit a; -:2987: @abstract @virtual function foo(); -:2988: `,0); -:2989: assertNotParse(` -:2990: unit a; -:2991: @abstract,virtual function foo(); -:2992: `,0); -:2993: assertNotParse(` -:2994: unit a; -:2995: @abstract,virtual foo(); -:2996: `,0); -:2997: assertNotParse(` -:2998: unit a; -:2999: @++,virtual foo(); -:3000: `,0); -:3001: assertParse(` -:3002: unit a; -:3003: function foo(): var s32; -:3004: `,0); -:3005:} -:3006: -:3007:@unittest function testProtDecl() -:3008:{ -:3009: assertNotParse(` -:3010: unit a; -:3011: protection; -:3012: `,0); -:3013: assertNotParse(` -:3014: unit a; -:3015: protection(private;a -:3016: `,0); -:3017: assertNotParse(` -:3018: unit a; -:3019: protection(p -:3020: `,0); -:3021: assertNotParse(` -:3022: unit a; -:3023: protection m -:3024: `,0); -:3025: assertNotParse(` -:3026: unit a; -:3027: protection() -:3028: `,0); -:3029:} -:3030: -:3031:@unittest function testVarDecl() -:3032:{ -:3033: assertNotParse(` -:3034: unit a; -:3035: var a var a; -:3036: `,0); -:3037: assertNotParse(` -:3038: unit a; -:3039: var a = var ; -:3040: `,0); -:3041: assertNotParse(` -:3042: unit a; -:3043: var T a = var 0; -:3044: `,0); -:3045: assertNotParse(` -:3046: unit a; -:3047: var T a = 0 var -:3048: `,0); -:3049: assertNotParse(` -:3050: unit a; -:3051: var T a] -:3052: `,0); -:3053: assertNotParse(` -:3054: unit a; -:3055: var T ++; -:3056: `,0); -:3057: assertNotParse(` -:3058: unit a; -:3059: var const T ++; -:3060: `,0); -:3061:} -:3062: -:3063:@unittest function testFlowStatements() -:3064:{ -:3065: assertParse(` -:3066: unit a; -:3067: function foo() -:3068: { -:3069: continue; -:3070: break; -:3071: goto @LBL; -:3072: } -:3073: `,0); -:3074: assertParse(` -:3075: unit a; -:3076: function foo() -:3077: { -:3078: continue @L0; -:3079: break @L0; -:3080: goto @L0; -:3081: } -:3082: `,0); -:3083: assertParse(` -:3084: unit a; -:3085: function foo() -:3086: { -:3087: continue afterExp; -:3088: break afterExp; -:3089: goto @lbl, afterExp; -:3090: } -:3091: `,0); -:3092: assertParse(` -:3093: unit a; -:3094: function foo() -:3095: { -:3096: continue @LBL, afterExp; -:3097: break @LBL, afterExp; -:3098: goto @LBL, afterExp; -:3099: } -:3100: `,0); -:3101: assertNotParse(` -:3102: unit a; -:3103: function foo() -:3104: { -:3105: goto; -:3106: } -:3107: `,0); -:3108: assertNotParse(` -:3109: unit a; -:3110: function foo() -:3111: { -:3112: break @ -:3113: } -:3114: `,0); -:3115: assertNotParse(` -:3116: unit a; -:3117: function foo() -:3118: { -:3119: goto -:3120: } -:3121: `,0); -:3122: assertNotParse(` -:3123: unit a; -:3124: function foo() -:3125: { -:3126: continue @, afterExp; -:3127: } -:3128: `,0); -:3129: assertNotParse(` -:3130: unit a; -:3131: function foo() -:3132: { -:3133: continue @, ; -:3134: } -:3135: `,0); -:3136: assertNotParse(` -:3137: unit a; -:3138: function foo() -:3139: { -:3140: continue , afterExp; -:3141: } -:3142: `,0); -:3143: assertNotParse(` -:3144: unit a; -:3145: function foo() -:3146: { -:3147: continue @; -:3148: } -:3149: `,0); -:3150: assertNotParse(` -:3151: unit a; -:3152: function foo() -:3153: { -:3154: continue @, %err; -:3155: } -:3156: `,0); -:3157: assertNotParse(` -:3158: unit a; -:3159: function foo() -:3160: { -:3161: continue %err; -:3162: } -:3163: `,0); -:3164: assertNotParse(` -:3165: unit a; -:3166: function foo() -:3167: { -:3168: continue @LBL, afterExp -:3169: } -:3170: `,0); -:3171:} -:3172: -:3173:@unittest function testImportDecl() -:3174:{ -:3175: assertParse(` -:3176: unit a; -:3177: import a.b, c.d, ; -:3178: `,echo(line)-2); -:3179: assertNotParse(` -:3180: unit a; -:3181: import; -:3182: `,echo(line)-2); -:3183: assertNotParse(` -:3184: unit a; -:3185: import a.; -:3186: `,echo(line)-2); -:3187: assertNotParse(` -:3188: unit a; -:3189: import a b; -:3190: `,echo(line)-2); -:3191: assertNotParse(` -:3192: unit a; -:3193: import("tant") a; -:3194: `,echo(line)-2); -:3195: assertNotParse(` -:3196: unit a; -:3197: import() a; -:3198: `,echo(line)-2); -:3199: assertNotParse(` -:3200: unit a; -:3201: import(0) a -:3202: `,echo(line)-2); -:3203: assertNotParse(` -:3204: unit a; -:3205: import(a) a; -:3206: `,echo(line)-2); -:3207: assertNotParse(` -:3208: unit a; -:3209: import(0 a; -:3210: `,echo(line)-2); -:3211: assertParse(` -:3212: unit a; -:3213: import a, b in c; -:3214: `,echo(line)-2); -:3215: assertParse(` -:3216: unit a; -:3217: import a in b; -:3218: `,echo(line)-2); -:3219: assertNotParse(` -:3220: unit a; -:3221: import in b; -:3222: `,echo(line)-2); -:3223: assertNotParse(` -:3224: unit a; -:3225: import a in b -:3226: `,echo(line)-2); -:3227: assertNotParse(` -:3228: unit a; -:3229: import a in ; -:3230: `,echo(line)-2); -:3231:} -:3232: -:3233:@unittest function testAggregateDecls() -:3234:{ -:3235: assertNotParse(` -:3236: unit a; -:3237: class {} -:3238: `,0); -:3239: assertNotParse(` -:3240: unit a; -:3241: struct {} -:3242: `,0); -:3243: assertNotParse(` -:3244: unit a; -:3245: union {} -:3246: `,0); -:3247: assertNotParse(` -:3248: unit a; -:3249: class A} -:3250: `,0); -:3251: assertNotParse(` -:3252: unit a; -:3253: struct A} -:3254: `,0); -:3255: assertNotParse(` -:3256: unit a; -:3257: class A : {} -:3258: `,0); -:3259: assertNotParse(` -:3260: unit a; -:3261: class A : B.C, {} -:3262: `,0); -:3263: assertNotParse(` -:3264: unit a; -:3265: class A : B.C, D. {} -:3266: `,0); -:3267: assertNotParse(` -:3268: unit a; -:3269: struct A : {} -:3270: `,0); -:3271: assertNotParse(` -:3272: unit a; -:3273: class A : A A{} -:3274: `,0); -:3275: assertNotParse(` -:3276: unit a; -:3277: class A{ var s8 a; -:3278: `,0); -:3279: assertNotParse(` -:3280: unit a; -:3281: struct A{ var s8 a; -:3282: `,0); -:3283: assertNotParse(` -:3284: unit a; -:3285: union A{ var s8 a; -:3286: `,0); -:3287: assertNotParse(` -:3288: unit a; -:3289: union A : {} -:3290: `,0); -:3291: assertParse(` -:3292: unit a; -:3293: union A {} -:3294: `,0); -:3295:} -:3296: -:3297:@unittest function testEnumDecl() -:3298:{ -:3299: assertParse(` -:3300: unit a; -:3301: enum A : B{ a = 1, @deprecated b = 2} -:3302: `,0); -:3303: assertNotParse(` -:3304: unit a; -:3305: enum A : {} -:3306: `,0); -:3307: assertNotParse(` -:3308: unit a; -:3309: enum A a { -:3310: `,0); -:3311: assertNotParse(` -:3312: unit a; -:3313: enum A {a a} -:3314: `,0); -:3315: assertNotParse(` -:3316: unit a; -:3317: enum {a} -:3318: `,0); -:3319: assertNotParse(` -:3320: unit a; -:3321: enum {a,++} -:3322: `,0); -:3323: assertNotParse(` -:3324: unit a; -:3325: enum A {} -:3326: `,0); -:3327: assertParse(` -:3328: unit a; -:3329: enum A {a,} -:3330: `,0); -:3331: assertNotParse(` -:3332: unit a; -:3333: enum A {a = 4; 3 2 1 0} -:3334: `,0); -:3335: assertParse(` -:3336: unit a; -:3337: enum A {a,b,} -:3338: `,0); -:3339: assertNotParse(` -:3340: unit a; -:3341: enum A {,} -:3342: `,0); -:3343: assertNotParse(` -:3344: unit a; -:3345: enum A { @INVALID a } -:3346: `,0); -:3347:} -:3348: -:3349:@unittest function testAliasAndType() -:3350:{ -:3351: assertParse(` -:3352: unit a; -:3353: alias MyPU64 = u64*; -:3354: `,0); -:3355: assertParse(` -:3356: unit a; -:3357: alias MyU64 = u64; -:3358: `,0); -:3359: assertParse(` -:3360: unit a; -:3361: alias Abc = a.B.C; -:3362: `,0); -:3363: assertNotParse(` -:3364: unit a; -:3365: alias; -:3366: `,0); -:3367: assertNotParse(` -:3368: unit a; -:3369: alias a; -:3370: `,0); -:3371: assertNotParse(` -:3372: unit a; -:3373: alias a.a; -:3374: `,0); -:3375: assertNotParse(` -:3376: unit a; -:3377: alias a = -:3378: `,0); -:3379: assertNotParse(` -:3380: unit a; -:3381: alias a = other -:3382: `,0); -:3383: assertParse(` -:3384: unit a; -:3385: alias a = function (): var s32; -:3386: `,0); -:3387: assertParse(` -:3388: unit a; -:3389: alias a => b; -:3390: `,0); -:3391: assertNotParse(` -:3392: unit a; -:3393: alias a => ; -:3394: `,0); -:3395: assertNotParse(` -:3396: unit a; -:3397: alias a => b -:3398: `,0); -:3399: assertNotParse(` -:3400: unit a; -:3401: alias a => a in in; -:3402: `,0); -:3403:} -:3404: -:3405:@unittest function testSuper() -:3406:{ -:3407: /*assertParse(` -:3408: unit a; -:3409: class A : B { var super superInstance;} -:3410: `,0); -:3411: assertNotParse(` -:3412: unit a; -:3413: class A : B { super superInstance;} -:3414: `,0);*/ -:3415: assertParse(` -:3416: unit a; -:3417: class A : B { function foo() {super.a();}} -:3418: `,0); -:3419: assertParse(` -:3420: unit a; -:3421: class A : B { function foo() {var auto b = super.a;}} -:3422: `,0); -:3423: assertParse(` -:3424: unit a; -:3425: class A : B { function foo() {super;}} -:3426: `,0); -:3427: assertNotParse(` -:3428: unit a; -:3429: class A : B { function foo() {super a;}} -:3430: `,0); -:3431: assertNotParse(` -:3432: unit a; -:3433: class A : B { function foo() {super .;}} -:3434: `,0); -:3435: /*assertParse(` -:3436: unit a; -:3437: class A : B { function foo() : super {return this:super;}} -:3438: `,0);*/ -:3439:} -:3440: -:3441:@unittest function testWhile() -:3442:{ -:3443: assertParse(` -:3444: unit a; -:3445: function foo() -:3446: { -:3447: while (true) do {} -:3448: } -:3449: `,0); -:3450: assertParse(` -:3451: unit a; -:3452: function foo() -:3453: { -:3454: while true && false do {} -:3455: } -:3456: `,0); -:3457: assertParse(` -:3458: unit a; -:3459: function foo() -:3460: { -:3461: while (a.b == true) do {} -:3462: } -:3463: `,0); -:3464: assertParse(` -:3465: unit a; -:3466: function foo() -:3467: { -:3468: while (true) do -:3469: while (true) do -:3470: {++a;--b;} -:3471: } -:3472: `,0); -:3473: assertNotParse(` -:3474: unit a; -:3475: function foo() -:3476: { -:3477: while (a) do { a a a -:3478: } -:3479: `,0); -:3480: assertNotParse(` -:3481: unit a; -:3482: function foo() -:3483: { -:3484: while (a) do -:3485: } -:3486: `,0); -:3487: assertNotParse(` -:3488: unit a; -:3489: function foo() -:3490: { -:3491: while (a) unit -:3492: } -:3493: `,0); -:3494: assertNotParse(` -:3495: unit a; -:3496: function foo() -:3497: { -:3498: while (a) unit do -:3499: } -:3500: `,0); -:3501: assertNotParse(` -:3502: unit a; -:3503: function foo() -:3504: { -:3505: while ( {} -:3506: } -:3507: `,0); -:3508: assertNotParse(` -:3509: unit a; -:3510: function foo() -:3511: { -:3512: while () do {} -:3513: } -:3514: `,0); -:3515: assertNotParse(` -:3516: unit a; -:3517: function foo() -:3518: { -:3519: while (true do {} -:3520: } -:3521: `,0); -:3522: assertParse(` -:3523: unit a; -:3524: function foo() -:3525: { -:3526: while true do {} -:3527: } -:3528: `,0); -:3529: assertNotParse(` -:3530: unit a; -:3531: function foo() -:3532: { -:3533: while (true; {} -:3534: } -:3535: `,0); -:3536:} -:3537: -:3538:@unittest function testForeach() -:3539:{ -:3540: assertParse(` -:3541: unit a; -:3542: function foo() -:3543: { -:3544: foreach(const s8 a) in b do {} -:3545: } -:3546: `,0); -:3547: assertNotParse(` -:3548: unit a; -:3549: function foo() -:3550: { -:3551: foreach(const s8 a) b do {} -:3552: } -:3553: `,0); -:3554: assertNotParse(` -:3555: unit a; -:3556: function foo() -:3557: { -:3558: foreach const s8 a = expr() in b do {} -:3559: } -:3560: `,0); -:3561: assertNotParse(` -:3562: unit a; -:3563: function foo() -:3564: { -:3565: foreach (const s8 a in b do {} -:3566: } -:3567: `,0); -:3568: assertParse(` -:3569: unit a; -:3570: function foo() -:3571: { -:3572: foreach const s8 a in b do {} -:3573: } -:3574: `,0); -:3575: assertNotParse(` -:3576: unit a; -:3577: function foo() -:3578: { -:3579: foreach(const s8 a, var s32 i) in b do {} -:3580: } -:3581: `,0); -:3582: assertParse(` -:3583: unit a; -:3584: function foo() -:3585: { -:3586: foreach(const s8 a; var s32 i) in b do {} -:3587: } -:3588: `,0); -:3589: assertParse(` -:3590: unit a; -:3591: function foo() -:3592: { -:3593: foreach const s8 a; var s32 i in b do {} -:3594: } -:3595: `,0); -:3596: assertParse(` -:3597: unit a; -:3598: function foo() -:3599: { -:3600: foreach (const s8 a) in 0..10 do {} -:3601: } -:3602: `,0); -:3603: assertNotParse(` -:3604: unit a; -:3605: function foo() -:3606: { -:3607: foreach(const s8 a) in 0.. do {} -:3608: } -:3609: `,0); -:3610: assertNotParse(` -:3611: unit a; -:3612: function foo() -:3613: { -:3614: foreach(const s8 a) in .. do {} -:3615: } -:3616: `,0); -:3617: assertNotParse(` -:3618: unit a; -:3619: function foo() -:3620: { -:3621: foreach(const a) in b do {} -:3622: } -:3623: `,0); -:3624: assertNotParse(` -:3625: unit a; -:3626: function foo() -:3627: { -:3628: foreach(const const a) in b do {} -:3629: } -:3630: `,0); -:3631: assertNotParse(` -:3632: unit a; -:3633: function foo() -:3634: { -:3635: foreach(const auto a ?) in b do {} -:3636: } -:3637: `,0); -:3638: assertNotParse(` -:3639: unit a; -:3640: function foo() -:3641: { -:3642: foreach(const auto a,) in b do {} -:3643: } -:3644: `,0); -:3645: assertParse(` -:3646: unit a; -:3647: function foo() -:3648: { -:3649: foreach const auto a in b do {} -:3650: } -:3651: `,0); -:3652: assertNotParse(` -:3653: unit a; -:3654: function foo() -:3655: { -:3656: foreach const auto a in b {} -:3657: } -:3658: `,0); -:3659: assertNotParse(` -:3660: unit a; -:3661: function foo() -:3662: { -:3663: foreach(a) in b do {} -:3664: } -:3665: `,0); -:3666: assertNotParse(` -:3667: unit a; -:3668: function foo() -:3669: { -:3670: foreach() in b do {} -:3671: } -:3672: `,0); -:3673: assertNotParse(` -:3674: unit a; -:3675: function foo() -:3676: { -:3677: foreach(a) in a a do {} -:3678: } -:3679: `,0); -:3680: assertNotParse(` -:3681: unit a; -:3682: function foo() -:3683: { -:3684: foreach a in b do {} -:3685: } -:3686: `,0); -:3687: assertNotParse(` -:3688: unit a; -:3689: function foo() -:3690: { -:3691: foreach(const auto a) in b do a a -:3692: } -:3693: `,0); -:3694: assertNotParse(` -:3695: unit a; -:3696: function foo() -:3697: { -:3698: foreach(const auto a) in b do ; -:3699: } -:3700: `,0); -:3701: assertNotParse(` -:3702: unit a; -:3703: function foo() -:3704: { -:3705: foreach(var auto a) in b] do {} -:3706: } -:3707: `,0); -:3708: assertNotParse(` -:3709: unit a; -:3710: function foo() -:3711: { -:3712: foreach(var auto a) in b] do {a] -:3713: } -:3714: `,0); -:3715: assertNotParse(` -:3716: unit a; -:3717: function foo() -:3718: { -:3719: foreach(auto a) in b] do {} -:3720: } -:3721: `,0); -:3722: assertNotParse(` -:3723: unit a; -:3724: function foo() -:3725: { -:3726: foreach(auto a) in b do { a++; a a a -:3727: } -:3728: `,0); -:3729: assertNotParse(` -:3730: unit a; -:3731: function foo() -:3732: { -:3733: foreach(const auto a) in b do {a a;++ -:3734: } -:3735: `,0); -:3736:} -:3737: -:3738:@unittest function testVariousErrors() -:3739:{ -:3740: assertNotParse(` -:3741: unit a; -:3742: function foo(@+ int b); -:3743: `,0); -:3744: assertNotParse(` -:3745: unit a; -:3746: var auto a = 8 -:3747: virtual unit b; -:3748: `,0); -:3749: assertNotParse(` -:3750: unit a; -:3751: function foo() -:3752: { -:3753: a = 8 -:3754: } -:3755: `,0); -:3756: assertNotParse(` -:3757: unit a; -:3758: function foo() -:3759: { -:3760: a =; -:3761: } -:3762: `,0); -:3763: assertNotParse(` -:3764: unit a; -:3765: A[0 b a; -:3766: `,0); -:3767: assertNotParse(` -:3768: unit a; -:3769: function foo() -:3770: { -:3771: a = -:3772: } -:3773: `,0); -:3774: assertNotParse(` -:3775: unit a; -:3776: function foo() -:3777: { -:3778: a = 8: ; -:3779: } -:3780: `,0); -:3781: assertNotParse(` -:3782: unit a; -:3783: enum A : s8[8:; -:3784: `,0); -:3785: assertNotParse(` -:3786: unit a; -:3787: function foo(s8[8 a); -:3788: `,0); -:3789: assertNotParse(``,0); -:3790: assertNotParse(` -:3791: unit a; -:3792: static identifier; -:3793: `,0); -:3794: assertNotParse(` -:3795: unit a; -:3796: struct Foo -:3797: { -:3798: unit a; -:3799: } -:3800: `,0); -:3801: assertNotParse(` -:3802: unit a; -:3803: struct Foo -:3804: { -:3805: virtual unit a; -:3806: } -:3807: `,0); -:3808: assertNotParse(` -:3809: unit a; -:3810: function foo() -:3811: { -:3812: if (true) {} else a a; -:3813: } -:3814: `,0); -:3815: assertNotParse(` -:3816: unit a; -:3817: function foo() -:3818: { -:3819: if (true) a a else a a; -:3820: } -:3821: `,0); -:3822: assertParse(` -:3823: unit a; -:3824: function foo() -:3825: { -:3826: if (true) do {} -:3827: else do if (true) do {} -:3828: else do {} -:3829: } -:3830: `,0); -:3831: assertParse(` -:3832: unit a; -:3833: function foo() -:3834: { -:3835: if (const auto a = 0) do {} -:3836: } -:3837: `,0); -:3838: assertParse(` -:3839: unit a; -:3840: function foo() -:3841: { -:3842: if (const s8 a = call()) do {} -:3843: } -:3844: `,0); -:3845: assertParse(` -:3846: unit a; -:3847: function foo() -:3848: { -:3849: if (var A.B a = call() && other()) do {} -:3850: } -:3851: `,0); -:3852: assertNotParse(` -:3853: unit a; -:3854: function foo() -:3855: { -:3856: if (var 0) do {} -:3857: } -:3858: `,0); -:3859: assertNotParse(` -:3860: unit a; -:3861: function foo() -:3862: { -:3863: if (const s8 a = 0; do {} -:3864: } -:3865: `,0); -:3866: assertNotParse(` -:3867: unit a; -:3868: function foo() -:3869: { -:3870: if (const s8 0 = 0) do {} -:3871: } -:3872: `,0); -:3873: assertParse(` -:3874: unit a; -:3875: function foo() -:3876: { -:3877: a = b % c; -:3878: } -:3879: `,0); -:3880: assertParse(` -:3881: unit a; -:3882: const auto a = ~1; -:3883: `,0); -:3884:} -:3885: -:3886:@unittest function testIfElse() -:3887:{ -:3888: assertParse(` -:3889: unit a; -:3890: function foo() -:3891: { -:3892: if (a) do -:3893: call(b); -:3894: } -:3895: `,0); -:3896: assertNotParse(` -:3897: unit a; -:3898: function foo() -:3899: { -:3900: if (a) do -:3901: call(b); -:3902: else -:3903: call(c); -:3904: } -:3905: `,0); -:3906: assertParse(` -:3907: unit a; -:3908: function foo() -:3909: { -:3910: if (a) do -:3911: { -:3912: call(b); -:3913: } -:3914: } -:3915: `,0); -:3916: assertParse(` -:3917: unit a; -:3918: function foo() -:3919: { -:3920: if (a) do -:3921: { -:3922: call(b); -:3923: call(b); -:3924: } -:3925: else do -:3926: { -:3927: how(c); -:3928: how(c); -:3929: } -:3930: } -:3931: `,0); -:3932: assertParse(` -:3933: unit a; -:3934: function foo() -:3935: { -:3936: if (a) do -:3937: call(b); -:3938: else do -:3939: can(c); -:3940: } -:3941: `,0); -:3942: assertParse(` -:3943: unit a; -:3944: function foo() -:3945: { -:3946: if (a) do -:3947: {} -:3948: else do -:3949: {} -:3950: } -:3951: `,0); -:3952: assertParse(` -:3953: unit a; -:3954: function foo() -:3955: { -:3956: if true do {that();} -:3957: } -:3958: `,0); -:3959: assertNotParse(` -:3960: unit a; -:3961: function foo() -:3962: { -:3963: if do that(); -:3964: } -:3965: `,0); -:3966: assertParse(` -:3967: unit a; -:3968: function foo() -:3969: { -:3970: if true do {} -:3971: } -:3972: `,0); -:3973: assertNotParse(` -:3974: unit a; -:3975: function foo() -:3976: { -:3977: if (a) do -:3978: else do -:3979: } -:3980: `,0); -:3981: assertNotParse(` -:3982: unit a; -:3983: function foo() -:3984: { -:3985: if (a) do { -:3986: else do } -:3987: } -:3988: `,0); -:3989: assertNotParse(` -:3990: unit a; -:3991: function foo() -:3992: { -:3993: if a) { -:3994: else do } -:3995: } -:3996: `,0); -:3997: assertNotParse(` -:3998: unit a; -:3999: function foo() -:4000: { -:4001: if (a do { -:4002: else } do -:4003: } -:4004: `,0); -:4005: assertNotParse(` -:4006: unit a; -:4007: function foo() -:4008: { -:4009: if (a do { -:4010: else do a a a -:4011: } -:4012: `,0); -:4013: assertNotParse(` -:4014: unit a; -:4015: function foo() -:4016: { -:4017: if (a do {} -:4018: else do { -:4019: } -:4020: `,0); -:4021: assertNotParse(` -:4022: unit a; -:4023: function foo() -:4024: { -:4025: if (a do {} -:4026: else do a a a { -:4027: } -:4028: `,0); -:4029: assertParse(` -:4030: unit a; -:4031: function foo() -:4032: { -:4033: a = false; -:4034: a = true; -:4035: a = null; -:4036: } -:4037: `,0); -:4038: assertNotParse(` -:4039: unit a; -:4040: function foo() -:4041: { -:4042: if (true; do {} -:4043: } -:4044: `,0); -:4045: assertNotParse(` -:4046: unit a; -:4047: function foo() -:4048: { -:4049: if (true) do {} -:4050: else do {a a;++ -:4051: } -:4052: `,0); -:4053:} -:4054: -:4055:@unittest function testSwitch() -:4056:{ -:4057: assertParse(` -:4058: unit a; -:4059: function foo() -:4060: { -:4061: switch(a) do -:4062: { -:4063: on (0,1) do a++; -:4064: else do a--; -:4065: } -:4066: } -:4067: `,0); -:4068: assertParse(` -:4069: unit a; -:4070: function foo() -:4071: { -:4072: switch a do -:4073: { -:4074: on 0,1 do a++; -:4075: else do a--; -:4076: } -:4077: } -:4078: `,0); -:4079: assertParse(` -:4080: unit a; -:4081: function foo() -:4082: { -:4083: switch(call()) do -:4084: { -:4085: on (0,1) do a++; -:4086: on (1,2) do a++; -:4087: } -:4088: } -:4089: `,0); -:4090: assertParse(` -:4091: unit a; -:4092: function foo() -:4093: { -:4094: switch(a) do -:4095: { -:4096: on (0..2) do a++; -:4097: else do a--; -:4098: } -:4099: } -:4100: `,0); -:4101: assertParse(` -:4102: unit a; -:4103: function foo() -:4104: { -:4105: switch(a) do -:4106: { -:4107: on (call1()..call2()) do a++; -:4108: else do a--; -:4109: } -:4110: } -:4111: `,0); -:4112: assertNotParse(` -:4113: unit a; -:4114: function foo() -:4115: { -:4116: switch(a) do -:4117: { -:4118: on (call1()..++) do a++; -:4119: else do a--; -:4120: } -:4121: } -:4122: `,0); -:4123: assertNotParse(` -:4124: unit a; -:4125: function foo() -:4126: { -:4127: switch(a) do -:4128: { -:4129: } -:4130: } -:4131: `,0); -:4132: assertNotParse(` -:4133: unit a; -:4134: function foo() -:4135: { -:4136: switch(a) do -:4137: { -:4138: on 0 do ; -:4139: else do #; -:4140: } -:4141: } -:4142: `,0); -:4143: assertNotParse(` -:4144: unit a; -:4145: function foo() -:4146: { -:4147: switch(call()) do -:4148: { -:4149: (0,1) do a++; -:4150: } -:4151: } -:4152: `,0); -:4153: assertNotParse(` -:4154: unit a; -:4155: function foo() -:4156: { -:4157: switch(call()) do -:4158: { -:4159: 0,1) a++; -:4160: } -:4161: } -:4162: `,0); -:4163: assertNotParse(` -:4164: unit a; -:4165: function foo() -:4166: { -:4167: switch(call()) -:4168: { -:4169: 0,1) a++; -:4170: } -:4171: } -:4172: `,0); -:4173: assertNotParse(` -:4174: unit a; -:4175: function foo() -:4176: { -:4177: switch(call()) do -:4178: { -:4179: (0,1) a++ + + -:4180: } -:4181: } -:4182: `,0); -:4183: assertNotParse(` -:4184: unit a; -:4185: function foo() -:4186: { -:4187: switch(call()) do -:4188: { -:4189: on (0,1) a++; -:4190: a++; -:4191: } -:4192: } -:4193: `,0); -:4194: assertNotParse(` -:4195: unit a; -:4196: function foo() -:4197: { -:4198: switch(call()) do -:4199: { -:4200: on 0,1) a++; -:4201: a++; -:4202: } -:4203: } -:4204: `,0); -:4205: assertNotParse(` -:4206: unit a; -:4207: function foo() -:4208: { -:4209: switch(call()) do -:4210: { -:4211: on (0;+; -:4212: } -:4213: } -:4214: `,0); -:4215: assertNotParse(` -:4216: unit a; -:4217: function foo() -:4218: { -:4219: switch(call()) do -:4220: { -:4221: on (, do -:4222: } -:4223: } -:4224: `,0); -:4225: assertNotParse(` -:4226: unit a; -:4227: function foo() -:4228: { -:4229: switch(call()) do -:4230: { -:4231: on (0,1) do a++ -:4232: } -:4233: } -:4234: `,0); -:4235: assertNotParse(` -:4236: unit a; -:4237: function foo() -:4238: { -:4239: switch a do -:4240: { -:4241: on 0 do # -:4242: -:4243: } -:4244: `,0); -:4245: assertNotParse(` -:4246: unit a; -:4247: function foo() -:4248: { -:4249: switch a do -:4250: { -:4251: on 0 do {} -:4252: -:4253: `,0); -:4254: assertNotParse(` -:4255: unit a; -:4256: function foo() -:4257: { -:4258: switch a do -:4259: { -:4260: on 0 do {} -:4261: else do # -:4262: } -:4263: `,0); -:4264: assertNotParse(` -:4265: unit a; -:4266: function foo() -:4267: { -:4268: switch(:: -:4269: { -:4270: on (0,1) do a++ -:4271: } -:4272: } -:4273: `,0); -:4274: assertNotParse(` -:4275: unit a; -:4276: function foo() -:4277: { -:4278: switch(a do -:4279: { -:4280: on (0,1) do a++ -:4281: } -:4282: } -:4283: `,0); -:4284: assertNotParse(` -:4285: unit a; -:4286: function foo() -:4287: { -:4288: switch(a) do -:4289: on (0,1) do a++ -:4290: } -:4291: `,0); -:4292: assertNotParse(` -:4293: unit a; -:4294: function foo() -:4295: { -:4296: switch a -:4297: on (0,1) a++ -:4298: } -:4299: `,0); -:4300: assertNotParse(` -:4301: unit a; -:4302: function foo() -:4303: { -:4304: switch(a) do -:4305: { -:4306: on (0,1) do a++; -:4307: else :; -:4308: } -:4309: } -:4310: `,0); -:4311: assertNotParse(` -:4312: unit a; -:4313: function foo() -:4314: { -:4315: switch(a) do -:4316: { -:4317: on (0,1) do a++; -:4318: else /*do*/{} -:4319: } -:4320: } -:4321: `,0); -:4322: assertNotParse(` -:4323: unit a; -:4324: function foo() -:4325: { -:4326: switch(a) do -:4327: { -:4328: on (0,1) do a++; -:4329: else do {} -:4330: -:4331: }`,0); -:4332: assertNotParse(` -:4333: unit a; -:4334: function foo() -:4335: { -:4336: switch a do -:4337: { -:4338: on 0 do ; -:4339: else do ; -:4340: on 1 do ; -:4341: } -:4342: } -:4343: `,0); -:4344: assertNotParse(` -:4345: unit a; -:4346: function foo() -:4347: { -:4348: switch a do -:4349: { -:4350: on 0 do {} -:4351: else do {} -:4352: `,0); -:4353:} -:4354: -:4355:@unittest function testInitializers() -:4356:{ -:4357: assertParse(` -:4358: unit a; -:4359: const auto a = 0:s8; -:4360: `,0); -:4361: assertNotParse(` -:4362: unit a; -:4363: const auto a 0:s8; -:4364: `,0); -:4365: assertParse(` -:4366: unit a; -:4367: const auto a = []; -:4368: `,0); -:4369: assertParse(` -:4370: unit a; -:4371: const auto a = [0]; -:4372: `,0); -:4373: assertParse(` -:4374: unit a; -:4375: const auto a = [0,1]; -:4376: `,0); -:4377: assertParse(` -:4378: unit a; -:4379: const auto a = [[0,1]]; -:4380: `,0); -:4381: assertParse(` -:4382: unit a; -:4383: const auto a = [[0,1],[2,3]]; -:4384: `,0); -:4385: assertNotParse(` -:4386: unit a; -:4387: const auto a = [0,1],[2,3]]; -:4388: `,0); -:4389: assertNotParse(` -:4390: unit a; -:4391: const auto a = [0,1][2,3]]; -:4392: `,0); -:4393: assertNotParse(` -:4394: unit a; -:4395: const auto a = 0,1],[2,3]]; -:4396: `,0); -:4397: assertNotParse(` -:4398: unit a; -:4399: const auto a = [; -:4400: `,0); -:4401: assertNotParse(` -:4402: unit a; -:4403: const auto a = ; -:4404: `,0); -:4405: assertParse(` -:4406: unit a; -:4407: function foo() -:4408: { -:4409: var s8[] a; -:4410: a = [0,1]; -:4411: } -:4412: `,0); -:4413: assertNotParse(` -:4414: unit a; -:4415: function foo() -:4416: { -:4417: var s8[] a; -:4418: a = [const -:4419: } -:4420: `,0); -:4421:} -:4422: -:4423:@unittest function testAssert() -:4424:{ -:4425: assertParse(` -:4426: unit a; -:4427: function foo() { assert(true == true); } -:4428: `,0); -:4429: assertNotParse(` -:4430: unit a; -:4431: function foo() { assert true == true); } -:4432: `,0); -:4433: assertNotParse(` -:4434: unit a; -:4435: function foo() { assert(true true); } -:4436: `,0); -:4437: assertNotParse(` -:4438: unit a; -:4439: function foo() { assert(true; } -:4440: `,0); -:4441: assertNotParse(` -:4442: unit a; -:4443: function foo() { assert(true) } -:4444: `,0); -:4445: assertNotParse(` -:4446: unit a; -:4447: function foo() { assert( } -:4448: `,0); -:4449: assertParse(` -:4450: unit a; -:4451: function foo() { assert(true, "NG"); } -:4452: `,0); -:4453: assertNotParse(` -:4454: unit a; -:4455: function foo() { assert(true,); } -:4456: `,0); -:4457: assertNotParse(` -:4458: unit a; -:4459: function foo() { assert(true, e^); } -:4460: `,0); -:4461:} -:4462: -:4463:@unittest function testLabel() -:4464:{ -:4465: assertParse(` -:4466: unit a; -:4467: function foo() { label L0; } -:4468: `,0); -:4469: assertNotParse(` -:4470: unit a; -:4471: function foo() { label; } -:4472: `,0); -:4473: assertNotParse(` -:4474: unit a; -:4475: function foo() { label L0 } -:4476: `,0); -:4477:} -:4478: -:4479:@unittest function testWith() -:4480:{ -:4481: assertParse(` -:4482: unit u; -:4483: function foo() -:4484: { -:4485: with (a, c.d, e.f[0].g()) do -:4486: { -:4487: call(); -:4488: other(); -:4489: } -:4490: } -:4491: `,0); -:4492: assertParse(` -:4493: unit u; -:4494: function foo() -:4495: { -:4496: with a, c.d, e.f[0].g() do -:4497: { -:4498: call(); -:4499: other(); -:4500: } -:4501: } -:4502: `,0); -:4503: assertParse(` -:4504: unit u; -:4505: function foo() -:4506: { -:4507: with (a, c.d, e.f[0].g()) do -:4508: singleStatement(); -:4509: } -:4510: `,0); -:4511: assertNotParse(` -:4512: unit u; -:4513: function foo() -:4514: { -:4515: with (/*no withScopes*/) do -:4516: singleStatement(); -:4517: } -:4518: `,0); -:4519: assertNotParse(` -:4520: unit u; -:4521: function foo() -:4522: { -:4523: with (a,) do -:4524: singleStatement(); -:4525: } -:4526: `,0); -:4527: assertNotParse(` -:4528: unit u; -:4529: function foo() -:4530: { -:4531: with a, do -:4532: singleStatement(); -:4533: } -:4534: `,0); -:4535: assertNotParse(` -:4536: unit u; -:4537: function foo() -:4538: { -:4539: with (a) do // no decl or statement -:4540: } -:4541: `,0); -:4542: assertNotParse(` -:4543: unit u; -:4544: function foo() -:4545: { -:4546: with (a!!!!notAnExpre!!!!, j) do { call(); } -:4547: } -:4548: `,0); -:4549: assertNotParse(` -:4550: unit u; -:4551: function foo() -:4552: { -:4553: with ( { call(); } -:4554: } -:4555: `,0); -:4556: assertNotParse(` -:4557: unit u; -:4558: function foo() -:4559: { -:4560: with (a { call(); } -:4561: } -:4562: `,0); -:4563: assertNotParse(` -:4564: unit u; -:4565: function foo() -:4566: { -:4567: with a { call(); } -:4568: } -:4569: `,0); -:4570: assertNotParse(` -:4571: unit u; -:4572: function foo() -:4573: { -:4574: with (a) { call(); } -:4575: } -:4576: `,0); -:4577:} -:4578: -:4579:@unittest function testForeignAggr() -:4580:{ -:4581: assertParse(` -:4582: unit u; -:4583: struct Foo; -:4584: class Foo; -:4585: union Foo; -:4586: `,0); -:4587:} -:4588: -:4589:@unittest function testCeeVariadics() -:4590:{ -:4591: assertParse(` -:4592: unit u; -:4593: function fun(...); -:4594: function fun(const s8 a; ...); -:4595: function fun(const s8 a; const s8 b; ...); -:4596: `, echo(line)-4); -:4597: assertNotParse(` -:4598: unit u; -:4599: function fun(@A const v...); -:4600: `, echo(line)-2); -:4601: assertNotParse(` -:4602: unit u; -:4603: function fun(...; -:4604: `, echo(line)-2); -:4605: assertNotParse(` -:4606: unit u; -:4607: function fun(var ...); -:4608: `, echo(line)-2); -:4609: assertNotParse(` -:4610: unit u; -:4611: function fun(...; const s8 b); -:4612: `, echo(line)-2); -:4613:} -:4614: -:4615:@unittest function testOverDecl() -:4616:{ -:4617: assertParse(` -:4618: unit u; -:4619: overload o { a,b,c } -:4620: `, echo(line)-2); -:4621: assertParse(` -:4622: unit u; -:4623: overload o { a,b,c, } -:4624: `, echo(line)-2); -:4625: assertNotParse(` -:4626: unit u; -:4627: overload o { } -:4628: `, echo(line)-2); -:4629: assertParse(` -:4630: unit u; -:4631: overload o { a.a, b.b, c.x } -:4632: `, echo(line)-2); -:4633: assertNotParse(` -:4634: unit u; -:4635: overload o { a a } -:4636: `, echo(line)-2); -:4637: assertNotParse(` -:4638: unit u; -:4639: overload o { -:4640: `, echo(line)-2); -:4641: assertNotParse(` -:4642: unit u; -:4643: overload o { a -:4644: `, echo(line)-2); -:4645: assertNotParse(` -:4646: unit u; -:4647: overload o a -:4648: `, echo(line)-2); -:4649: assertNotParse(` -:4650: unit u; -:4651: overload { a } -:4652: `, echo(line)-2); -:4653: assertParse(` -:4654: unit u; -:4655: overload o : o { a } -:4656: `, echo(line)-2); -:4657: assertNotParse(` -:4658: unit u; -:4659: overload o : 1 { a } -:4660: `, echo(line)-2); -:4661:} -:4662: -:4663:@unittest function testExplicitThisParam() -:4664:{ -:4665: assertParse(` -:4666: unit u; -:4667: function fun(var T this); -:4668: function fun(var T this; s32 a); -:4669: `, echo(line)-3); -:4670: assertParse(` -:4671: unit u; -:4672: alias Fun = function fun(var T this); -:4673: `, echo(line)-2); -:4674: assertNotParse(` -:4675: unit u; -:4676: function fun(var T this; var T this); -:4677: function fun(s32 a; var T this); -:4678: `, echo(line)-3); -:4679:} -:4680: -:4681:@unittest function testCondexp() -:4682:{ -:4683: assertParse(` -:4684: unit u; -:4685: function f() -:4686: { -:4687: a ? b() else c(); -:4688: } -:4689: `, echo(line)-5); -:4690: assertParse(` -:4691: unit u; -:4692: function f() -:4693: { -:4694: a ? b(); -:4695: } -:4696: `, echo(line)-5); -:4697: assertParse(` -:4698: unit u; -:4699: function f() -:4700: { -:4701: x = a in b ? 0 else 1 + q; -:4702: } -:4703: `, echo(line)-5); -:4704: assertNotParse(` -:4705: unit u; -:4706: function f() -:4707: { -:4708: x = b ? # else 1; -:4709: } -:4710: `, echo(line)-5); -:4711: assertNotParse(` -:4712: unit u; -:4713: function f() -:4714: { -:4715: x = b ? 0 else #; -:4716: } -:4717: `, echo(line)-5); -:4718: assertNotParse(` -:4719: unit u; -:4720: function f() -:4721: { -:4722: x = b ? 0 1; -:4723: } -:4724: `, echo(line)-5); -:4725: assertNotParse(` -:4726: unit u; -:4727: function f() -:4728: { -:4729: const auto a = ["a" "b"]; -:4730: } -:4731: `, echo(line)-5); -:4732:} -:4733: -:4734:@unittest function testContinueBreakOn() -:4735:{ -:4736: assertParse(` -:4737: unit u; -:4738: function f() -:4739: { -:4740: continue on; -:4741: } -:4742: `, echo(line)-5); -:4743: assertParse(` -:4744: unit u; -:4745: function f() -:4746: { -:4747: continue on e; -:4748: } -:4749: `, echo(line)-5); -:4750: assertParse(` -:4751: unit u; -:4752: function f() -:4753: { -:4754: continue on else; -:4755: } -:4756: `, echo(line)-5); -:4757: assertNotParse(` -:4758: unit u; -:4759: function f() -:4760: { -:4761: continue on -:4762: } -:4763: `, echo(line)-5); -:4764: assertNotParse(` -:4765: unit u; -:4766: function f() -:4767: { -:4768: continue on else -:4769: } -:4770: `, echo(line)-5); -:4771: assertNotParse(` -:4772: unit u; -:4773: function f() -:4774: { -:4775: continue on %e -:4776: } -:4777: `, echo(line)-5); -:4778: assertParse(` -:4779: unit u; -:4780: function f() -:4781: { -:4782: break on; -:4783: } -:4784: `, echo(line)-5); -:4785: assertNotParse(` -:4786: unit u; -:4787: function f() -:4788: { -:4789: break on 0; -:4790: } -:4791: `, echo(line)-5); -:4792: assertNotParse(` -:4793: unit u; -:4794: function f() -:4795: { -:4796: break on -:4797: } -:4798: `, echo(line)-5); -:4799:} -:4800: -:4801:@unittest function testAsmExp() -:4802:{ -:4803: assertParse(` -:4804: unit u; -:4805: function f() -:4806: { -:4807: asm("code"); -:4808: } -:4809: `, echo(line)-5); -:4810: assertParse(` -:4811: unit u; -:4812: function f() -:4813: { -:4814: asm("code"): s32; -:4815: } -:4816: `, echo(line)-5); -:4817: assertParse(` -:4818: unit u; -:4819: function f() -:4820: { -:4821: asm("code", "constraint"): s32; -:4822: } -:4823: `, echo(line)-5); -:4824: assertParse(` -:4825: unit u; -:4826: function f() -:4827: { -:4828: asm("code", "constraint", 1, 2 ,3): s32; -:4829: } -:4830: `, echo(line)-5); -:4831: assertNotParse(` -:4832: unit u; -:4833: function f() -:4834: { -:4835: asm("code", "constraint", 1, 2 3): s32; -:4836: } -:4837: `, echo(line)-5); -:4838: assertNotParse(` -:4839: unit u; -:4840: function f() -:4841: { -:4842: asm(0); -:4843: } -:4844: `, echo(line)-5); -:4845: assertNotParse(` -:4846: unit u; -:4847: function f() -:4848: { -:4849: asm("code", 0); -:4850: } -:4851: `, echo(line)-5); -:4852: assertNotParse(` -:4853: unit u; -:4854: function f() -:4855: { -:4856: asm("code", "constraint", #); -:4857: } -:4858: `, echo(line)-5); -:4859: assertNotParse(` -:4860: unit u; -:4861: function f() -:4862: { -:4863: asm(0): #; -:4864: } -:4865: `, echo(line)-5); -:4866: assertNotParse(` -:4867: unit u; -:4868: function f() -:4869: { -:4870: asm; -:4871: } -:4872: `, echo(line)-5); -:4873: assertNotParse(` -:4874: unit u; -:4875: function f() -:4876: { -:4877: asm("sdf"): #; -:4878: } -:4879: `, echo(line)-5); -:4880:} -:4881: -:4882:@unittest function testStaticAssert() -:4883:{ -:4884: assertParse(` -:4885: unit u; -:4886: static assert(0); -:4887: `, echo(line)-2); -:4888: assertNotParse(` -:4889: unit u; -:4890: static assert(#); -:4891: `, echo(line)-2); -:4892: assertNotParse(` -:4893: unit u; -:4894: var static assert(0); -:4895: `, echo(line)-2); -:4896: assertNotParse(` -:4897: unit u; -:4898: static var assert(0); -:4899: `, echo(line)-2); -:4900:} -:4901: -:4902:@unittest function testEchoExp() -:4903:{ -:4904: assertParse(` -:4905: unit a; -:4906: function Foo(){ if (echo(verb)) do {} } -:4907: `,0); -:4908: assertParse(` -:4909: unit a; -:4910: function Foo(){ if (echo(verb, T, s8[])) do {} } -:4911: `,0); -:4912: assertNotParse(` -:4913: unit a; -:4914: function Foo(){ if (echo } -:4915: `,0); -:4916: assertNotParse(` -:4917: unit a; -:4918: function Foo(){ if (echo( } -:4919: `,0); -:4920: assertNotParse(` -:4921: unit a; -:4922: function Foo(){ if (echo(a^ } -:4923: `,0); -:4924: assertNotParse(` -:4925: unit a; -:4926: function Foo(){ if (echo() do } -:4927: `,0); -:4928: assertNotParse(` -:4929: unit a; -:4930: function Foo(){ if (echo(verb,) } -:4931: `,0); -:4932: assertNotParse(` -:4933: unit a; -:4934: function Foo(){ if (echo(verb,p0]) } -:4935: `,0); -:4936: assertNotParse(` -:4937: unit a; -:4938: function Foo(){ if (echo(verb,{p0;) } -:4939: `,0); -:4940: assertParse(` -:4941: unit a; -:4942: function Foo(){ if (echo(verb, p0+8)) do {} } -:4943: `,0); -:4944: assertNotParse(` -:4945: unit a; -:4946: function Foo(){ if (echo(isType, T, class)) do {} } -:4947: `,0); -:4948: assertParse(` -:4949: unit a; -:4950: function Foo(){ if echo(version) do {} } -:4951: `,0); -:4952:} -:4953: -:4954:@unittest function testLambdaExp() -:4955:{ -:4956: assertParse(` -:4957: unit u; -:4958: var auto e = function(s32 a) => false; -:4959: `, echo(line)-2); -:4960: assertParse(` -:4961: unit u; -:4962: var auto e = function(s32 a) => {return false;}; -:4963: `, echo(line)-2); -:4964: assertParse(` -:4965: unit u; -:4966: var auto e = function() => 0; -:4967: `, echo(line)-2); -:4968: assertNotParse(` -:4969: unit u; -:4970: var auto e = function() 0; -:4971: `, echo(line)-2); -:4972: assertNotParse(` -:4973: unit u; -:4974: var auto e = function() => }; -:4975: `, echo(line)-2); -:4976: assertNotParse(` -:4977: unit u; -:4978: var auto e = function() => #; -:4979: `, echo(line)-2); -:4980: assertNotParse(` -:4981: unit u; -:4982: var auto e = function() => {#; -:4983: `, echo(line)-2); -:4984: assertNotParse(` -:4985: unit u; -:4986: var auto e = function() {0;}; -:4987: `, echo(line)-2); -:4988: assertNotParse(` -:4989: unit u; -:4990: var auto e = function) => {return ~}; -:4991: `, echo(line)-2); -:4992: assertNotParse(` -:4993: unit u; -:4994: function f() {return ~} -:4995: `, echo(line)-2); -:4996:} -:4997: -:4998:@unittest function testMultIndexes() -:4999:{ -:5000: assertParse(` -:5001: unit u; -:5002: var auto e = a[1,2]; -:5003: `, echo(line)-2); -:5004: assertNotParse(` -:5005: unit u; -:5006: var auto e = a[1,]; -:5007: `, echo(line)-2); -:5008: assertNotParse(` -:5009: unit u; -:5010: var auto e = a[1,2; -:5011: `, echo(line)-2); -:5012: assertParse(` -:5013: unit u; -:5014: var auto e = a[]; -:5015: `, echo(line)-2); -:5016: assertParse(` -:5017: unit u; enum A : s32 = 255; -:5018: `, echo(line)-1); -:5019: assertNotParse(` -:5020: unit u; enum A : s32 = [1,; -:5021: `, echo(line)-1); -:5022: assertNotParse(` -:5023: unit u; enum A : s32 = 255 -:5024: `, echo(line)-1); -:5025:} -:5026: -:5027:@unittest function testNewDelete() -:5028:{ -:5029: assertParse(` -:5030: unit u; -:5031: var auto e = new C; -:5032: `, echo(line) - 2 ); -:5033: assertParse(` -:5034: unit u; -:5035: var auto e = new(C); -:5036: `, echo(line) - 2); -:5037: assertParse(` -:5038: unit u; -:5039: var auto e = new(Mallocator, C); -:5040: `, echo(line) - 2); -:5041: assertParse(` -:5042: unit u; -:5043: var auto e = new(Mallocator, C).create(p0, p1); -:5044: `, echo(line) - 2); -:5045: assertParse(` -:5046: unit u; -:5047: function f(){ delete c; } -:5048: `, echo(line) - 2); -:5049: assertParse(` -:5050: unit u; -:5051: function f(){ delete (c); } -:5052: `, echo(line) - 2); -:5053: assertParse(` -:5054: unit u; -:5055: function f(){ delete (Mallocator, c); } -:5056: `, echo(line) - 2); -:5057: assertNotParse(` -:5058: unit u; -:5059: var auto e = new(); -:5060: `, echo(line) - 2); -:5061: assertNotParse(` -:5062: unit u; -:5063: var auto e = new(,); -:5064: `, echo(line) - 2); -:5065: assertNotParse(` -:5066: unit u; -:5067: var auto e = new(c; -:5068: `, echo(line) - 2); -:5069: assertNotParse(` -:5070: unit u; -:5071: var auto e = new(c,); -:5072: `, echo(line) - 2); -:5073: assertNotParse(` -:5074: unit u; -:5075: var auto e = new(c,c; -:5076: `, echo(line) - 2); -:5077: assertNotParse(` -:5078: unit u; -:5079: function f(){ delete (, c); } -:5080: `, echo(line) - 2); -:5081: assertNotParse(` -:5082: unit u; -:5083: function f(){ delete; } -:5084: `, echo(line) - 2); -:5085: assertNotParse(` -:5086: unit u; -:5087: function f(){ delete (c,; } -:5088: `, echo(line) - 2); -:5089: assertNotParse(` -:5090: unit u; -:5091: function f(){ delete (c, c; } -:5092: `, echo(line) - 2); -:5093: assertNotParse(` -:5094: unit u; -:5095: function f(){ delete (c; } -:5096: `, echo(line) - 2); -:5097:} -:5098: -:5099:@unittest function testSelfParse() -:5100:{ -:5101: echo(filename).fileRead().assertParse(0); -:5102:} -:5103: -:5104:@unittest function testVersionBlockDecl() -:5105:{ -:5106: assertParse(` -:5107: unit a; -:5108: version(a) do const s8 b; -:5109: `, echo(line) - 2); -:5110: assertNotParse(` -:5111: unit a; -:5112: version a) do const s8 b; -:5113: `, echo(line) - 2); -:5114: assertNotParse(` -:5115: unit a; -:5116: version (a do const s8 b; -:5117: `, echo(line) - 2); -:5118: assertParse(` -:5119: unit a; -:5120: version(a) do const s8 b; else do const s16 b; -:5121: `, echo(line) - 2); -:5122: assertParse(` -:5123: unit a; -:5124: version(a || b) do const s8 c; -:5125: `, echo(line) - 2); -:5126: assertNotParse(` -:5127: unit a; -:5128: version(a ||) do const s8 c; -:5129: `, echo(line) - 2); -:5130: assertParse(` -:5131: unit a; -:5132: version(a && b) do const s8 c; -:5133: `, echo(line) - 2); -:5134: assertNotParse(` -:5135: unit a; -:5136: version(a &&) do const s8 c; -:5137: `, echo(line) - 2); -:5138: assertNotParse(` -:5139: unit a; -:5140: version(&) do const s8 c; -:5141: `, echo(line) - 2); -:5142: assertNotParse(` -:5143: unit a; -:5144: version do const s8 c; -:5145: `, echo(line) - 2); -:5146: assertParse(` -:5147: unit a; -:5148: version(a && b || c) do const s8 d; -:5149: `, echo(line) - 2); -:5150: assertParse(` -:5151: unit a; -:5152: version(a || b && c) do const s8 d; -:5153: `, echo(line) - 2); -:5154: assertParse(` -:5155: unit a; -:5156: version((a || b) && c) do const s8 d; -:5157: `, echo(line) - 2); -:5158: assertParse(` -:5159: unit a; -:5160: version((a || b) && (c)) do const s8 d; -:5161: `, echo(line) - 2); -:5162: assertParse(` -:5163: unit a; -:5164: version((a || b) && (c || d)) do const s8 e; -:5165: `, echo(line) - 2); -:5166: assertParse(` -:5167: unit a; -:5168: version(a) do {const s8 b;} else do {const s16 b;} -:5169: `, echo(line) - 2); -:5170: assertNotParse(` -:5171: unit a; -:5172: version() do {const s8 b;} -:5173: `, echo(line) - 2); -:5174: assertNotParse(` -:5175: unit a; -:5176: version(a && ;) do {const s8 b;} -:5177: `, echo(line) - 2); -:5178: assertNotParse(` -:5179: unit a; -:5180: version(a & ()) do {const s8 b;} -:5181: `, echo(line) - 2); -:5182: assertNotParse(` -:5183: unit a; -:5184: version(a) do const -:5185: `, echo(line) - 2); -:5186: assertNotParse(` -:5187: unit a; -:5188: version(a) do {const s8 b;} else do const -:5189: `, echo(line) - 2); -:5190: assertNotParse(` -:5191: unit a; -:5192: version(a) do {const;} -:5193: `, echo(line) - 2); -:5194: assertNotParse(` -:5195: unit a; -:5196: version(a) do {const A a;} else do {const} -:5197: `, echo(line) - 2); -:5198: assertNotParse(` -:5199: unit a; -:5200: version(a) do {} else {} -:5201: `, echo(line) - 2); -:5202:} -:5203: -:5204:@unittest function testVersionBlockStatement() -:5205:{ -:5206: assertParse(` -:5207: unit a; -:5208: function foo(){version(a) do ++b;} -:5209: `, echo(line) - 2); -:5210: assertParse(` -:5211: unit a; -:5212: function foo(){version(!a) do ++b;} -:5213: `, echo(line) - 2); -:5214: assertParse(` -:5215: unit a; -:5216: function foo(){version(a && !b) do ++b;} -:5217: `, echo(line) - 2); -:5218: assertNotParse(` -:5219: unit a; -:5220: function foo(){version a) do const s8 b;} -:5221: `, echo(line) - 2); -:5222: assertNotParse(` -:5223: unit a; -:5224: function foo(){version (a do const s8 b;} -:5225: `,0); -:5226: assertParse(` -:5227: unit a; -:5228: function foo(){version(a) do const s8 b; else do const s16 b;} -:5229: `,0); -:5230: assertParse(` -:5231: unit a; -:5232: function foo(){version(a || b) do const s8 c;} -:5233: `,0); -:5234: assertNotParse(` -:5235: unit a; -:5236: function foo(){version(a ||) do const s8 c;} -:5237: `,0); -:5238: assertParse(` -:5239: unit a; -:5240: function foo(){version(a && b) do const s8 c;} -:5241: `,0); -:5242: assertNotParse(` -:5243: unit a; -:5244: function foo(){version(a &&)do const s8 c;} -:5245: `,0); -:5246: assertNotParse(` -:5247: unit a; -:5248: function foo(){version(&&) do const s8 c;} -:5249: `,0); -:5250: assertNotParse(` -:5251: unit a; -:5252: function foo(){version do const s8 c;} -:5253: `,0); -:5254: assertParse(` -:5255: unit a; -:5256: function foo(){version(a && b || c) do const s8 d;} -:5257: `,0); -:5258: assertParse(` -:5259: unit a; -:5260: function foo(){version(a || b && c) do const s8 d;} -:5261: `,0); -:5262: assertParse(` -:5263: unit a; -:5264: function foo(){version((a || b) && c) do const s8 d;} -:5265: `,0); -:5266: assertParse(` -:5267: unit a; -:5268: function foo(){version((a || b) && (c)) do const s8 d;} -:5269: `,0); -:5270: assertParse(` -:5271: unit a; -:5272: function foo(){version((a || b) && (c || d)) do const s8 e;} -:5273: `,0); -:5274: assertParse(` -:5275: unit a; -:5276: function foo(){version(a) do {const s8 b;} else do {const s16 b;}} -:5277: `,0); -:5278: assertNotParse(` -:5279: unit a; -:5280: function foo(){version() do {const s8 b;}} -:5281: `,0); -:5282: assertNotParse(` -:5283: unit a; -:5284: function foo(){version(a && ;) do {const s8 b;}} -:5285: `,0); -:5286: assertNotParse(` -:5287: unit a; -:5288: function foo(){version(a && ()) do {const s8 b;}} -:5289: `,0); -:5290: assertNotParse(` -:5291: unit a; -:5292: function foo(){version(a) do const} -:5293: `,0); -:5294: assertNotParse(` -:5295: unit a; -:5296: function foo(){version(a) do {const s8 b;} else do const} -:5297: `,0); -:5298: assertNotParse(` -:5299: unit a; -:5300: function foo(){version(a) do {const}} -:5301: `,0); -:5302: assertNotParse(` -:5303: unit a; -:5304: function foo(){version(a) do {const A a;} else do {const}} -:5305: `,0); -:5306: assertNotParse(` -:5307: unit a; -:5308: function foo(){version(a) do {const A a;} else /*do*/ {const}} -:5309: `,0); -:5310: assertNotParse(` -:5311: unit a; -:5312: function foo(){version(a#) do {}} -:5313: `,0); -:5314:} -:5315: -:5316:@unittest function testTuples() -:5317:{ -:5318: assertParse(` -:5319: unit u; -:5320: var auto e = (0,0); -:5321: `,echo(line) - 2); -:5322: assertParse(` -:5323: unit u; -:5324: var auto e = (0,0+0); -:5325: `,echo(line) - 2); -:5326: assertParse(` -:5327: unit u; -:5328: var auto e = (0,0,(0,0)); -:5329: `,0); -:5330: assertNotParse(` -:5331: unit u; -:5332: var auto e = (0,; -:5333: `,echo(line) - 2); -:5334: assertNotParse(` -:5335: unit u; -:5336: var auto e = (0,0%; -:5337: `,echo(line) - 2); -:5338: assertNotParse(` -:5339: unit u; -:5340: var auto e = (,); -:5341: `,echo(line) - 2); -:5342: -:5343: assertParse(` -:5344: unit u; -:5345: var (s32, s32) e; -:5346: `,echo(line) - 2); -:5347: assertParse(` -:5348: unit u; -:5349: var (s32, (s32, s32)) e; -:5350: `,echo(line) - 2); -:5351: assertNotParse(` -:5352: unit u; -:5353: var (s32,) e; -:5354: `,echo(line) - 2); -:5355: assertNotParse(` -:5356: unit u; -:5357: var (s32, e; -:5358: `,echo(line) - 2); -:5359: assertNotParse(` -:5360: unit u; -:5361: var s32,s32) e; -:5362: `,echo(line) - 2); -:5363: -:5364: assertParse(` -:5365: unit u; -:5366: var (s32, s32)[0..0] e; -:5367: `,echo(line) - 2); -:5368: assertParse(` -:5369: unit u; -:5370: var (s32, s32)[0,0] e; -:5371: var (s32, s32, s32)[0,0,0] e; -:5372: `,echo(line) - 2); -:5373: -:5374: assertNotParse(` -:5375: unit u; -:5376: var (s32, s32)[0..] e; -:5377: `,echo(line) - 2); -:5378: assertNotParse(` -:5379: unit u; -:5380: var (s32, s32)[0,] e; -:5381: `,echo(line) - 2); -:5382: assertNotParse(` -:5383: unit u; -:5384: var (s32, s32)[0, e; -:5385: `,echo(line) - 2); -:5386: assertNotParse(` -:5387: unit u; -:5388: var (s32, s32)[0,0 e; -:5389: `,echo(line) - 2); -:5390: assertNotParse(` -:5391: unit u; -:5392: var (if) e; -:5393: `,echo(line) - 2); -:5394:} -:5395: -:5396:@unittest function testAttribs() -:5397:{ -:5398: assertParse(` -:5399: unit a; -:5400: @operator("in") function foo(); -:5401: `,0); -:5402: assertParse(` -:5403: unit a; -:5404: @@metadata(42,13) function foo(); -:5405: `,0); -:5406: assertNotParse(` -:5407: unit a; -:5408: @@metadata(42,) function foo(); -:5409: `,0); -:5410: assertNotParse(` -:5411: unit a; -:5412: @@metadata(42,+ function foo(); -:5413: `,0); -:5414: assertNotParse(` -:5415: unit a; -:5416: @@metadata(42# function foo(); -:5417: `,0); -:5418: assertNotParse(` -:5419: unit a; -:5420: @@metadata() function foo(); -:5421: `,0); -:5422: var auto line = echo(line) + 2; -:5423: assertNotParse(` -:5424: unit u; -:5425: @asm(0,0,0,0,0) function f1(){} -:5426: @deprecated(0,0,0,0,0) var s32 a03; -:5427: @foreign(0,0,0,0,0) var s32 a06; -:5428: @inline(0,0,0,0) var s32 a12; -:5429: @inline("maybe") function f1(){} -:5430: @LLVM(0,0,0,0) var s32 a12; -:5431: @operator function f1(){} -:5432: @overload(0,0,0) function f1(){} -:5433: @private(0) function f1(){} -:5434: @protected(0) function f1(){} -:5435: @public(0) function f1(){} -:5436: @strict(0) function f1(){} -:5437: @unittest(0,0,0,0) var s32 a11; -:5438: `, line); -:5439: assertNotParse(`unit u; @abstract(0) var s32 a;`, echo(line)); -:5440: assertNotParse(`unit u; @constructor(0) var s32 a;`, echo(line)); -:5441: assertNotParse(`unit u; @destructor(0) var s32 a;`, echo(line)); -:5442: assertNotParse(`unit u; @final(0) var s32 a;`, echo(line)); -:5443: assertNotParse(`unit u; @noinit(0) var s32 a;`, echo(line)); -:5444: assertNotParse(`unit u; @noopt(0) var s32 a;`, echo(line)); -:5445: assertNotParse(`unit u; @override(0) var s32 a;`, echo(line)); -:5446: assertNotParse(`unit u; @return(0) var s32 a;`, echo(line)); -:5447: assertNotParse(`unit u; @tls(0) var s32 a;`, echo(line)); -:5448: assertNotParse(`unit u; @virtual(0) var s32 a;`, echo(line)); -:5449: assertNotParse(`unit u; @noreturn(0) function a();`, echo(line)); -:5450: line = echo(line) + 2; -:5451: assertParse(` -:5452: unit u; -:5453: @abstract @abstract var s32 a00; -:5454: @constructor @constructor var s32 a02; -:5455: @deprecated @deprecated var s32 a03; -:5456: @destructor @destructor var s32 a04; -:5457: @final @final var s32 a06; -:5458: @foreign @foreign var s32 a06; -:5459: @override @override var s32 a07; -:5460: @virtual @virtual var s32 a09; -:5461: @unittest @unittest var s32 a11; -:5462: @inline @inline var s32 a12; -:5463: @LLVM @LLVM var s32 a12; -:5464: @overload(0) function f1(); -:5465: @return @return function f1(){} -:5466: @noopt @noopt var s32 a11; -:5467: @private @public var s32 a11; -:5468: @protected @strict var s32 a11; -:5469: @operator(a+b) @operator(a+b) var s32 a11; -:5470: @tls @tls var s32 a11; -:5471: @asm(0) @asm(0) var s32 a11; -:5472: @noinit @noinit var s32 a11; -:5473: @noreturn @noreturn function f(); -:5474: `, line); -:5475:} -:5476: -:5477:@unittest function testSuperStcNotAllowedOnDecl() -:5478:{ -:5479: assertNotParse(`unit u; const alias a = b;`, echo(line)); -:5480: assertNotParse(`unit u; const import a;`, echo(line)); -:5481: assertNotParse(`unit u; const label a;`, echo(line)); -:5482: assertNotParse(`unit u; const enum A {a}`, echo(line)); -:5483: assertNotParse(`unit u; const protection(public)`, echo(line)); -:5484: assertNotParse(`unit u; const version a do {}`, echo(line)); -:5485: assertNotParse(`unit u; const static assert(0);`, echo(line)); -:5486: assertNotParse(`unit u; const overload A {a}`, echo(line)); -:5487:} -:5488: -:5489:@unittest function testUnitAndImportAfterGrammRefact() -:5490:{ -:5491: assertNotParse(`unit u*;`, echo(line)); -:5492: assertNotParse(`unit u[][]; `, echo(line)); -:5493: assertNotParse(`unit u; import a[];`, echo(line)); -:5494: assertNotParse(`unit u; import s32`, echo(line)); -:5495: assertNotParse(`unit u:[1];`, echo(line)); -:5496:} -:5497: -:5498:@unittest function testAsmBody() -:5499:{ -:5500: assertParse(`unit u; function a() = asm 0;`, echo(line)); -:5501: assertNotParse(`unit u; function a() =`, echo(line)); -:5502: assertNotParse(`unit u; function a() = asm`, echo(line)); -:5503: assertNotParse(`unit u; function a() = asm 0`, echo(line)); -:5504: assertNotParse(`unit u; function a() = asm ;`, echo(line)); -:5505: assertNotParse(`unit u; function a() = asm #;`, echo(line)); -:5506:} -:5507: -:5508:@unittest function testGenericParameters() -:5509:{ -:5510: assertParse(`unit u; function a[T](T t);`, echo(line)); -:5511: assertParse(`unit u; function a[T, U](T t);`, echo(line)); -:5512: assertNotParse(`unit u; function [] a();`, echo(line)); -:5513: assertNotParse(`unit u; function a[();`, echo(line)); -:5514: assertNotParse(`unit u; function a[T();`, echo(line)); -:5515: assertNotParse(`unit u; function a[T, ();`, echo(line)); -:5516: assertNotParse(`unit u; function a[T,] ();`, echo(line)); -:5517:} -:5518: -:5519:@unittest function testGenericApplication() -:5520:{ -:5521: assertParse(`unit u; var auto a = apply(g, 0);`, echo(line)); -:5522: assertParse(`unit u; var auto a = apply(g, s32, 0);`, echo(line)); -:5523: assertNotParse(`unit u; var auto a = apply(g, s32, 0;`, echo(line)); -:5524: assertNotParse(`unit u; var auto a = apply(g, s32,;`, echo(line)); -:5525: assertNotParse(`unit u; var auto a = apply(g, s32, 0;`, echo(line)); -:5526: assertNotParse(`unit u; var auto a = apply(g,#`, echo(line)); -:5527: assertNotParse(`unit u; var auto a = apply(g;`, echo(line)); -:5528: assertNotParse(`unit u; var auto a = apply(;`, echo(line)); -:5529: assertNotParse(`unit u; var auto a = apply;`, echo(line)); -:5530: assertNotParse(`unit u; var auto a = apply();`, echo(line)); -:5531: assertParse(`unit u; alias T = apply(g, 0); var T t;`, echo(line)); -:5532: assertNotParse(`unit u; alias T = apply(g, #`, echo(line)); -:5533: assertParse(`unit u; var auto a = g:[0,0];`, echo(line)); -:5534: assertNotParse(`unit u; var auto a = g:[#;`, echo(line)); -:5535: assertNotParse(`unit u; var auto a = g:[#;`, echo(line)); -:5536: assertNotParse(`unit u; var auto a = g:[0;`, echo(line)); -:5537: assertNotParse(`unit u; var auto a = g:[0,;`, echo(line)); -:5538: assertNotParse(`unit u; var auto a = g:[0,]`, echo(line)); -:5539: assertParse(`unit u; var G:[I,I] a;`, echo(line)); -:5540: assertNotParse(`unit u; var G:[I,] a;`, echo(line)); -:5541: assertNotParse(`unit u; var G:[I, a;`, echo(line)); -:5542: assertNotParse(`unit u; var G:[] a;`, echo(line)); -:5543: assertNotParse(`unit u; var G:[] a;`, echo(line)); -:5544: assertNotParse(`unit u; var G:[ a;`, echo(line)); -:5545: assertNotParse(`unit u; var apply(G,T*) gt;`, echo(line)); -:5546:} -:5547: -:5548:@unittest function testLambdaAlias() -:5549:{ -:5550: assertParse(`unit u; alias a = function(): s32 => 0;`, echo(line)); -:5551: assertNotParse(`unit u; alias a = function(): s32 =>;`, echo(line)); -:5552:} -:5553: -:5554:@unittest function testTypeEcho() -:5555:{ -:5556: assertParse(`unit u; alias a = echo(type,0);`, echo(line)); -:5557: assertParse(`unit u; var echo(type,0)[+] arr;`, echo(line)); -:5558: assertNotParse(`unit u; alias a = echo(type,0`, echo(line)); -:5559:} -:5560: -:5561:@unittest function miscCov1() -:5562:{ -:5563: assertNotParse(`unit u; function f(){foreach var auto a; s32 b do {} }`, echo(line)); -:5564: assertNotParse(`unit u; alias f = function()[ `, echo(line)); -:5565: assertParse(`unit u; alias F = (function(): var s32); `, echo(line)); -:5566: assertNotParse(`unit u; import oops:[0];`, echo(line)); -:5567:} <<<<<< EOF # path=src/styx/position.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/position.sx -: 1:unit styx.position; -: 2: -: 3:/// Stores a position in the source code. -: 4:struct Position -: 5:{ -: 6: /// The line, 1-based. -: 7: var u32 line; -: 8: /// The column, 1-based. -: 9: var u32 column; -:10: /// -:11: @constructor function create(u32 line; u32 column) -:12: { 26:13: this.line = line; 26:14: this.column = column; 26:15: } -:16: /// -:17: function compare(Position other): s32 -:18: { 40218:19: var s32 result = line - other.line; 40218:20: if !result do 391:21: result = column - other.column; 40218:22: return result; -:23: } -:24: /// -:25: @operator(a!=b) function opNE(Position other): bool -:26: { 1:27: return compare(other) != 0; -:28: } -:29: /// -:30: @operator(a==b) function opEQ(Position other): bool -:31: { 1:32: return compare(other) == 0; -:33: } -:34: /// -:35: @operator(ab) function opGT(Position other): bool -:46: { 18605:47: return compare(other) > 0; -:48: } -:49: /// -:50: @operator(a>=b) function opGE(Position other): bool -:51: { 2:52: return compare(other) >= 0; -:53: } -:54:} -:55: -:56:@unittest function test1() -:57:{ -:58: assert(Position.create(0,0) < Position.create(0,1)); -:59: assert(Position.create(0,0) < Position.create(1,1)); -:60: assert(Position.create(1,0) < Position.create(1,1)); -:61: -:62: assert(Position.create(0,0) <= Position.create(0,1)); -:63: assert(Position.create(0,0) <= Position.create(1,1)); -:64: assert(Position.create(1,0) <= Position.create(1,1)); -:65: assert(Position.create(1,1) <= Position.create(1,1)); -:66: -:67: assert(Position.create(2,0) > Position.create(1,0)); -:68: assert(Position.create(2,1) > Position.create(2,0)); -:69: assert(Position.create(2,1) >= Position.create(2,0)); -:70: assert(Position.create(2,3) >= Position.create(2,3)); -:71: -:72: assert(Position.create(0,0) == Position.create(0,0)); -:73: assert(Position.create(1,0) != Position.create(0,0)); -:74:} <<<<<< EOF # path=src/styx/sar.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/sar.sx -: 1:unit styx.sar; -: 2: -: 3:/// Styx archive item -: 4:struct SarItem -: 5:{ -: 6: /// the original file name -: 7: var s8[] fname; -: 8: /// the source -: 9: var s8[] code; -: 10: /// its line offset in the archive -: 11: var u32 line; -: 12:} -: 13: -: 14:/// Tries to parse $(D data) as a sar archive. -: 15:function parseSar(s8[] data; var SarItem[+] result): bool -: 16:{ -: 17: var s32 line; -: 18: var s32 column; -: 19: -: 20: // skip shebang line 60: 21: if data.length > 2 && data[0..2] == "#!" do -: 22: { 4: 23: data = data[2 .. $]; 4: 24: while data.length do -: 25: { 104: 26: if data[0] == "\n" do -: 27: { 4: 28: data = data[1 .. $]; 4: 29: line += 1; 4: 30: column = 0; 4: 31: break; -: 32: } 100: 33: data = data[1 .. $]; -: 34: } -: 35: } -: 36: 60: 37: while true do -: 38: { -: 39: // check paragraph char 138: 40: if data.length < 2 || !(column == 0 && data[0 .. 2] == "§") do 5: 41: return false; -: 42: 133: 43: result.length += 1; 133: 44: data = data[2 .. $]; -: 45: -: 46: // read sx fname -: 47: var usize fnameLen; 133: 48: while ++fnameLen < data.length do -: 49: { 789: 50: if data[fnameLen] == "\n" do -: 51: { 133: 52: line += 1; 133: 53: column = 1; 133: 54: var usize b = fnameLen; 133: 55: while (data[b] == " " || data[b] == "\t" || data[b] == "\n" || data[b] == "\r") do 137: 56: --b; 133: 57: result[$ - 1].line = line; 133: 58: result[$ - 1].fname = data[0 .. b + 1]; 133: 59: data = data[fnameLen + 1 .. $]; 133: 60: break; -: 61: } -: 62: } -: 63: -: 64: // read content -: 65: var usize srcLen; 133: 66: while srcLen < data.length do -: 67: { 18137: 68: if srcLen + 1 < data.length && data[srcLen .. srcLen + 2] == "§" do -: 69: { 79: 70: if column != 0 do 1: 71: return false; -: 72: 78: 73: result[$ - 1].code = data[0 .. srcLen - 1]; 78: 74: data = data[srcLen .. $]; 78: 75: break; -: 76: } 18058: 77: else do if srcLen == data.length - 1 do -: 78: { 54: 79: result[$ - 1].code = data; 54: 80: data = data[0 .. 0]; 54: 81: break; -: 82: } 18004: 83: if data[srcLen] == "\n" do -: 84: { 1299: 85: column = 0; 1299: 86: line += 1; -: 87: } 16705: 88: else do column++; 18004: 89: srcLen++; -: 90: } 132: 91: if data.length == 0 do 54: 92: return true; -: 93: } -: 94:} -: 95: -: 96:@unittest function test1() -: 97:{ -: 98: const s8[] src = -: 99:"#!sfsdfdsf sdf sdf sdf sfds -:100:§a.sx\t\t -:101:unit a; -:102:§b.sx -:103:unit b; -:104:§c/d.sx -:105:unit c.d;"; -:106: var SarItem[+] result; -:107: assert(parseSar(src, result)); -:108: assert(result.length == 3); -:109: assert(result[0].fname == "a.sx"); -:110: assert(result[0].code == "unit a;"); -:111: assert(result[1].fname == "b.sx"); -:112: assert(result[1].code == "unit b;"); -:113: assert(result[2].fname == "c/d.sx"); -:114: assert(result[2].code == "unit c.d;"); -:115:} -:116: -:117:@unittest function test2() -:118:{ -:119: const s8[] src = -:120:"#!sfsdfdsf sdf sdf sdf sfds -:121: §a.sx\t\t -:122:unit a; -:123:§b.sx -:124:unit b; -:125:§c/d.sx -:126:unit c.d;"; -:127: var SarItem[+] result; -:128: assert(!parseSar(src, result)); -:129:} -:130: -:131:@unittest function test3() -:132:{ -:133: const s8[] src = -:134:"#!sfsdfdsf sdf sdf sdf sfds -:135:§a.sx\t\t -:136:unit a; -:137://§b.sx -:138:unit b; -:139:§c/d.sx -:140:unit c.d;"; -:141: var SarItem[+] result; -:142: assert(!parseSar(src, result)); -:143:} -:144: -:145:/// Shebang must start on first char -:146:@unittest function test4() -:147:{ -:148: const s8[] src = -:149:" -:150:#!sfsdfdsf sdf sdf sdf sfds -:151:§a.sx"; -:152: var SarItem[+] result; -:153: assert(!parseSar(src, result)); -:154:} -:155: -:156:/// file names are prefixed with a paragraph grapheme -:157:@unittest function test5() -:158:{ -:159: const s8[] src = -:160:"#!sfsdfdsf sdf sdf sdf sfds -:161:a.sx"; -:162: var SarItem[+] result; -:163: assert(!parseSar(src, result)); -:164:} <<<<<< EOF # path=src/styx/scope.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/scope.sx -: 1:unit styx.scope; -: 2: -: 3:@private import -: 4: styx.symbol, -: 5: styx.ast.base, -: 6: styx.ast.declarations, -: 7: styx.ast.statements, -: 8: ; -: 9: -: 10:enum ScopeFlag : u16 -: 11:{ -: 12: isResolvingCall, // expsema, allow to try UFC -: 13: isTryingWithSymbols, // expsema, allow to skip attempts of resolving using the "with syms" -: 14: isInInitializer, // expsema, called for `var Type a = exp` -: 15: doSkipAdhocSema, // typesema, allow to prevent "ad-hoc" declSema -: 16: firstOverloadPass, // expsema, trying overloads targeting exact parameters type -: 17: isResolvingOverload, // expsema, trying to see if a call to an over member works -: 18: isDotDotted, // expsema, the dot prefix is already solved, do not try the "with syms" -: 19: isInSwitchElse, // stmtsema, "continue on else" must be rejected -: 20: isInGeneric, // expsema, within a generic, not callable -: 21:} -: 22: -: 23:alias ScopeFlags = bool[ScopeFlag]; -: 24: -: 25:/// To solve in scope of `with ... do` -: 26:struct WithExpression -: 27:{ -: 28: /// The expression used as DotExp lhs -: 29: @noinit @@Semantic var Expression* exp; -: 30: /// The symbol used for a strict search -: 31: @noinit @@Semantic var Symbol* searchSym; -: 32: /// -: 33: @constructor function create(Expression* exp; Symbol* searchSym) -: 34: { 1618: 35: this.exp = exp; 1618: 36: this.searchSym = searchSym; 1618: 37: } -: 38: /// The symbol is not really an explicit with exp and must be tried as last resort -: 39: @destructor function destroy() -: 40: { -: 41: // Scope.withSyms is an array of values so this dtor + no copy construction would corrupt the array -: 42: //if isEnumParent do -: 43: // exp.free(); 23: 44: } -: 45:} -: 46: -: 47:/** -: 48: * Maintain information about the symbol used to resolve identifiers, -: 49: * the current function, the most nested loop and the additional symbols -: 50: * used to resolve in the statement owned by a `with()`. -: 51: */ -: 52:class Scope -: 53:{ -: 54: -: 55:protection(private) -: 56: -: 57: function copy(): Scope* -: 58: { 248326: 59: var Scope* res = (new Scope).create(sym, filename); 248326: 60: res.withSyms = withSyms; 248326: 61: res.func = func; 248326: 62: res.loop = loop; 248326: 63: res.$switch = $switch; 248326: 64: res.flags = flags; 248326: 65: res.array = array; 248326: 66: res.tempOwner = tempOwner; 248326: 67: res.enumSym = enumSym; 248326: 68: res.previous = this; 248326: 69: res.currentStatement = currentStatement; -: 70: 248326: 71: return res; -: 72: } -: 73: -: 74: var Scope* previous; -: 75: -: 76:protection(public) -: 77: -: 78: /// The `Symbol` used to resolve identifiers. -: 79: var Symbol* sym; -: 80: /// Additional symbols allowing to resolve in a `with ... do`. -: 81: var WithExpression[+] withSyms; -: 82: /// -: 83: var WithExpression* enumSym; -: 84: /// The current function. -: 85: var FunctionDeclaration* func; -: 86: /// The current loop. -: 87: var Statement* loop; -: 88: /// The current switch. -: 89: var SwitchStatement* $switch; -: 90: /// To solve `$` -: 91: var Expression* array; -: 92: /// so that front-end-generated locals can be collected for locals management -: 93: /// (the current scope in unaries (e.g CallExp) does no always match to a BlockStatement) -: 94: var Symbol* tempOwner; -: 95: /// -: 96: var ScopeFlags flags; -: 97: /// -: 98: var s8[] filename; -: 99: /// -:100: var Statement* currentStatement; -:101: -:102: /// Constructs a new root `Scope`. Should only be called when a `UnitDeclaration` is visited. -:103: @constructor function create(Symbol* sym; s8[] filename) -:104: { 248832:105: this.sym = sym; 248832:106: this.filename = filename; 248832:107: } -:108: -:109: /// -:110: @destructor function destroy() -:111: { 261:112: withSyms.decref; 261:113: } -:114: -:115: /// Returns: A nested `Scope` but equal to the current one. -:116: function pushNested(): Scope* -:117: { 208565:118: return copy(); -:119: } -:120: -:121: /// Returns: A nested `Scope` based on the given `.sym`. -:122: function pushSym(Symbol* sym; bool isTempOwner = false): Scope* -:123: { 28816:124: var Scope* result = copy(); 28816:125: result.sym = sym; 28816:126: if isTempOwner do 13695:127: result.tempOwner = sym; 28816:128: return result; -:129: } -:130: -:131: /// Returns: A nested `Scope` based on the given `agg`. -:132: function pushAggregate(Declaration* agg): Scope* -:133: { 1060:134: var Scope* result= copy(); 1060:135: result.sym = agg.symbol; 1060:136: result.withSyms.length = 0; 1060:137: result.enumSym = null; 1060:138: result.func = null; 1060:139: result.loop = null; 1060:140: result.$switch = null; 1060:141: result.array = null; 1060:142: result.tempOwner= null; 1060:143: return result; -:144: } -:145: -:146: /// Returns: A nested `Scope` based on the given `loop`. -:147: function pushLoop(Statement* loop): Scope* -:148: { 2127:149: var Scope* result= copy(); 2127:150: result.sym = loop.symbol; 2127:151: result.loop = loop; 2127:152: return result; -:153: } -:154: -:155: /// Returns: A nested `Scope` based on the given `switch`. -:156: function pushSwitch(SwitchStatement* $switch): Scope* -:157: { 287:158: var Scope* result= copy(); 287:159: result.$switch = $switch; 287:160: result.flags -= isInSwitchElse; 287:161: return result; -:162: } -:163: -:164: /// Returns: A nested `Scope` based on the given `func`. -:165: function pushFunc(FunctionDeclaration* func): Scope* -:166: { 5599:167: var Scope* result= copy(); 5599:168: result.sym = func.symbol; 5599:169: result.func = func; 5599:170: result.array = null; 5599:171: return result; -:172: } -:173: -:174: /// Returns: A nested `Scope` with `array`. to solve `$` -:175: function pushDollar(Expression* array): Scope* -:176: { 1872:177: var Scope* result = copy(); 1872:178: result.array = array; 1872:179: return result; -:180: } -:181: -:182: /// Returns: The parent `Scope`. -:183: function pop(): Scope* -:184: { 199760:185: var auto result = previous; 199760:186: return result; -:187: } -:188: -:189: /// Returns: the parent function -:190: function parentFunc(): Declaration* -:191: { 27:192: var auto f = this.func:u8*; 27:193: var auto s = this; 27:194: while s.func:u8* == f do 153:195: s = s.pop(); 27:196: return s.func; -:197: } -:198: -:199: /** -:200: * Overwrite the symbol used to resolve. -:201: * -:202: * This operation cannot be reverted with `pop()` and should only used -:203: * during expression semantics. -:204: * -:205: * Returns: -:206: * The previous resolution symbol, that can be then restored later. -:207: */ -:208: function setSym(Symbol* sym): Symbol* -:209: { 70735:210: var Symbol* result = this.sym; 70735:211: this.sym = sym; 70735:212: return result; -:213: } -:214: -:215: /// Returns: if it exists then the ancestor scope that defines `s` as resolution symbol -:216: /// and otherwise `null`. -:217: function getScopeWithSym(Symbol* s): Scope* -:218: { 7:219: var auto result = this; 7:220: while result && result.sym != s do 29:221: result = result.pop(); 7:222: return result; -:223: } -:224:} <<<<<< EOF # path=src/styx/semantic.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/semantic.sx -: 1:/// Drives the semantic passes -: 2:unit styx.semantic; -: 3: -: 4:@private import -: 5: styx.session, -: 6: styx.ast.base, -: 7: styx.ast.declarations, -: 8: styx.semantic.$protection, -: 9: styx.semantic.symbolize, -:10: styx.semantic.imports, -:11: styx.semantic.declarations, -:12: styx.semantic.bodies, -:13: ; -:14: -:15:/** -:16: * Prepare a unit before running the true semantic. -:17: * -:18: * - evaluate `version`s, and suppress the content of invalid ones -:19: * - create the symbols and the scopes attached to the nodes -:20: * - set the nodes .filename field -:21: * - set the nodes protection -:22: * -:23: * Params: -:24: * node = The AST produced by a parser. All the units of a program must be processed. -:25: */ -:26:function preSemantic(UnitDeclaration* node): bool -:27:{ 505:28: symbolizeUnit(node); 505:29: setProtections(node); -:30: 505:31: return !session.hasErrors(); -:32:} -:33: -:34:/** -:35: * Associates imports to their matching units. -:36: * -:37: * Params: -:38: * node = The AST produced by a parser. All the units of a program must be processed. -:39: */ -:40:function linkImports(UnitDeclaration* node): bool -:41:{ 488:42: attachImports(node); 488:43: return !session.hasErrors(); -:44:} -:45: -:46:/** -:47: * Checks the semantics in a unit -:48: * -:49: * - Declarations are checked -:50: * - In function bodies -:51: * - statements are checked -:52: * - identifiers and named types are resolved. -:53: * - expressions are converted, checked, their type is determined -:54: * -:55: * Params: -:56: * unit = The AST produced by a parser. The process starts from the -:57: * given unit and jumps automatically in the imports. -:58: */ -:59:function semantic(UnitDeclaration* node): bool -:60:{ 472:61: declarationSemantic(node); 472:62: bodiesSemantic(node); 472:63: return !session.hasErrors(); -:64:} <<<<<< EOF # path=src/styx/session.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/session.sx -: 1:unit styx.session; -: 2: -: 3:@private import -: 4: system, -: 5: styx.position, -: 6: styx.lexer, -: 7: styx.parser, -: 8: ; -: 9: -: 10:/// Describes the type of a message -: 11:enum MessageType : u8 -: 12:{ -: 13: /// error -: 14: error, -: 15: /// information, e.g in verbose mode -: 16: info, -: 17: /// warning -: 18: warn, -: 19: /// deprecation -: 20: dep, -: 21:} -: 22: -: 23:/// Describes how warning are handled -: 24:enum WarningType : u8 -: 25:{ -: 26: // warnings are enabled -: 27: enabled, -: 28: // warnings are not emitted -: 29: disabled, -: 30: // warnings stop compilation -: 31: error, -: 32:} -: 33: -: 34:/// Describes what the backend produces -: 35:enum BackendOutputKind : u8 -: 36:{ -: 37: // executable -: 38: exe, -: 39: // linkable object -: 40: obj, -: 41: // archive -: 42: ar, -: 43: // linkable source asm (".s") -: 44: $asm, -: 45: // target agnostic bitcode -: 46: bc, -: 47: // target agnostic and readable representation -: 48: ir, -: 49:} -: 50: -: 51:enum AdditionalCheck : u8 -: 52:{ -: 53: // generate code to check AssertStatement that are not verifiable during compilation -: 54: asserts, -: 55: // generate code to check array access that violate the array lenth -: 56: bounds, -: 57: // generate code to check null this on member variable accesses -: 58: dotvars, -: 59: // generate code to check uncovered switches matches -: 60: switches, -: 61: // generate code to check if member func are called with null this -: 62: thiscalls, -: 63: // statically check the intermediate representation -: 64: ir, -: 65:} -: 66: -: 67:alias AdditionalChecks = bool[AdditionalCheck]; -: 68: -: 69:// Describes the lint() modules -: 70:enum LinterModule : u16 -: 71:{ -: 72: suggestOptAss, -: 73: suggestCondExp, -: 74: suggestBreakExp, -: 75: suggestCondToLogical, -: 76: unusedImports, -: 77: unusedLocals, -: 78: assignInAssert, -: 79: reslice, -: 80: loopInvariant, -: 81:} -: 82: -: 83:// Set of linter modules -: 84:alias LinterModules = bool[LinterModule]; -: 85: -: 86:alias MessageFunc = (static function(MessageType type; s8[+] filename; Position pos; s8* spec; va_list* va))*; -: 87: -: 88:/// contains the fields of the target triplet -: 89:struct MachineTarget -: 90:{ -: 91: static var s8[+] cpu; -: 92: static var s8[+] vendor; -: 93: static var s8[+] os; -: 94: static var s8[+][+] features; -: 95: -: 96: @destructor static function free() -: 97: { 374: 98: cpu.decref; 374: 99: vendor.decref; 374:100: os.decref; 374:101: features.decref; 374:102: } -:103: -:104: static function setCpu(s8[] value): bool -:105: { 1:106: cpu = value; 1:107: return false; -:108: } -:109: -:110: static function setVendor(s8[] value): bool -:111: { 1:112: vendor = value; 1:113: return false; -:114: } -:115: -:116: static function setOs(s8[] value): bool -:117: { 1:118: os = value; 1:119: return false; -:120: } -:121: -:122: static function addFeature(s8[] value): bool -:123: { 7:124: switch value[0] do -:125: { 6:126: on "-", "+" do {} -:127: else do 1:128: return printMessageAndReturnTrue("`mattr` arguments must be prefixed with `+` (activate) or `-` (deactivate)"); -:129: } 6:130: foreach const auto f in features do 5:131: if f == value do 2:132: return false; 4:133: features.length++; 4:134: features[$-1] = value; 4:135: return false; -:136: } -:137: -:138: static function getTriple(): s8[+] -:139: { -:140: @return var s8[+] result; -:141: 273:142: if !cpu.length do -:143: { 181:144: cpu = session.ptr_size == 32 ? "i386"[] else "x86_64"[]; -:145: } 454:146: if !vendor.length do vendor = "unknown"; 273:147: if !os.length do -:148: { -:149: version linux do os = "linux-gnu"; -:150: } -:151: 273:152: result ~= cpu; 273:153: result ~= "-"; 273:154: result ~= vendor; 273:155: result ~= "-"; 273:156: result ~= os; 273:157: result ~= 0; 273:158: return result; -:159: } -:160: -:161: static function getFeatures(): s8[+] -:162: { -:163: @return var s8[+] result; 273:164: foreach (const auto i; const auto f) in features do -:165: { 2:166: result ~= f; 2:167: if i != features.length-1 do 1:168: result ~= ","; -:169: } 273:170: result ~= 0; 273:171: return result; -:172: } -:173:} -:174: -:175:struct LexerParserPair -:176:{ -:177: @constructor function createForFile(s8[] filename; bool isImport) -:178: { 390:179: this.filename = filename; 390:180: this.isImport = isImport; 390:181: this.lexer = (new Lexer).createFromFile(filename, true); 390:182: this.parser = (new Parser).create(lexer, isImport); 390:183: } -:184: -:185: @constructor function createForText(s8[] filename; s8[] code; u32 line; u32 column) -:186: { 130:187: this.filename = filename; 130:188: this.lexer = (new Lexer).createFromText(code, filename, line, column, true); 130:189: this.parser = (new Parser).create(lexer, false); 130:190: this.isImport = false; 130:191: } -:192: -:193: @destructor function destroy() -:194: { 520:195: filename.decref; -:196: // for now types are shared with expressions -:197: // so delete only the lexer -:198: // once fixed delete only the parser, that will delete the lexer, -:199: // and its production too -:200: version none do delete parser; 520:201: else do delete lexer; 520:202: } -:203: -:204: var s8[+] filename; -:205: @noinit var bool isImport; -:206: @noinit var Lexer* lexer; -:207: @noinit var Parser* parser; -:208:} -:209: -:210:/** -:211: * Represents a compiler session, which includes the messages, utilities to -:212: * append them, some global options. -:213: */ -:214:struct Session -:215:{ -:216:protection(strict) -:217: -:218: static var usize _errorsCount; -:219: static var usize _gaggedErrorCount; -:220: static var ssize _gag; -:221: -:222:protection(public) -:223: -:224: @constructor static function staticCtor() -:225: { -:226: version X86 do ptr_size = 32; 374:227: else do version X86_64 do ptr_size = 64; -:228: else do static assert(0); 374:229: beDir = ".styx"; 374:230: } -:231: -:232: @destructor static function staticDtor() -:233: { 374:234: versions.decref; 374:235: objects.decref; 374:236: outputFilename.decref; 374:237: beDir.decref; 374:238: libc.decref; 374:239: libc32.decref; 374:240: libc64.decref; 374:241: imports.decref; 374:242: additionalLinkerArgs.decref; 374:243: foreach var auto lpp in lexerParserPairs do 520:244: delete lpp; 374:245: lexerParserPairs.decref; 374:246: } -:247: -:248: /// always perform foreachBCE -:249: static var bool foreachBCE; -:250: /// verbose foreachBCE -:251: static var bool vforeachBCE; -:252: /// always perform escapeUsedCheck -:253: static var bool escapeUsed; -:254: /// verbose escapeUsedCheck -:255: static var bool vescapeUsed; -:256: /// Indicates if verbose output is expected. -:257: static var bool verbose; -:258: /// advanced support classes and full support of RcArrays is provided -:259: static var bool hasRtl; -:260: /// The directory where the backend output stuff -:261: static var s8[+] beDir; -:262: /// A callback for the messages. -:263: static var MessageFunc messageFunc = &defaultMessageFunc; -:264: /// List of objects used when producing an executable. -:265: static var s8[][+] objects; -:266: /// The program filename. -:267: static var s8[+] outputFilename; -:268: /// path to the binaries of an alternative C library -:269: static var s8[+] libc; -:270: static var s8[+] libc32; -:271: static var s8[+] libc64; -:272: -:273: static var bool noTlsEscapes; -:274: -:275: /// -:276: static var LexerParserPair*[+] lexerParserPairs; -:277: -:278: /// files for *.o and *.a headers -:279: static var s8[+][+] imports; -:280: -:281:// --------------------- -:282: -:283: /// If debug info are generated -:284: static var bool generateDebugInfo; -:285: -:286: /// if debug info are used to measure coverage -:287: static var bool gcov; -:288: static function setGcov(bool value): bool -:289: { 1:290: gcov = true; 1:291: generateDebugInfo = true; 1:292: addVersionInternal("gcov"); 1:293: return false; -:294: } -:295: -:296:// --------------------- -:297: -:298: /// if instrumentation for coverage is enabled -:299: static var bool cover; -:300: static function setCov(bool value): bool -:301: { 6:302: cover = true; 6:303: addVersionInternal("cov"); 6:304: return false; -:305: } -:306: -:307:// --------------------- -:308: -:309: /// Contains the version identifiers. -:310: static var s8[+][+] versions; -:311:protection(private) -:312: static function addVersionInternal(s8[+] value) -:313: { 8:314: versions ~= value; 8:315: } -:316:protection(public) -:317: static function addVersion(s8[] value): bool -:318: { 6:319: switch value do -:320: { -:321: on "all", "none", "X86_64", "X86", -:322: "check_asserts", "check_bounds", "check_switches", "check_thiscalls", "unittests", -:323: "gcov", "cov" do -:324: { 1:325: return printMessageAndReturnTrue(("error, version `" ~ value ~ "` is reserved").ptr); -:326: } 1:327: else do addVersionInternal(value); -:328: } 1:329: return false; -:330: } -:331: -:332:// --------------------- -:333: -:334: static var AdditionalChecks additionalChecks; -:335: static function addAdditionalCheck(s8[] value): bool -:336: { 165:337: if value == "all" do -:338: { 149:339: additionalChecks = additionalChecks.max; 149:340: return false; -:341: } 16:342: else do if value == "none" do -:343: { 4:344: additionalChecks = 0; 4:345: return false; -:346: } 12:347: else do if value == "default" do -:348: { 1:349: additionalChecks = [AdditionalCheck.bounds, AdditionalCheck.switches]; 1:350: return false; -:351: } -:352: 11:353: var bool include = true; 11:354: if value[0] == "-" do -:355: { 3:356: value = value[1 .. value.length]; 3:357: include = false; -:358: } 8:359: else do if value[0] == "+" do -:360: { 7:361: value = value[1 .. value.length]; 7:362: include = true; -:363: } 33:364: switch value do -:365: { 0:366: on "ir" do additionalChecks[ir] = include; 2:367: on "bounds" do additionalChecks[bounds] = include; 4:368: on "asserts" do additionalChecks[asserts] = include; 1:369: on "dotvars" do additionalChecks[dotvars] = include; 1:370: on "switches" do additionalChecks[switches] = include; 2:371: on "thiscalls" do additionalChecks[thiscalls] = include; 1:372: else do return printMessageAndReturnTrue(("invalid additional check, expected `asserts`, `dotvars`, `bounds`, `switches` or `thiscalls`, not `" ~ value ~ "`\0").ptr); -:373: } 10:374: return false; -:375: } -:376:// --------------------- -:377: -:378: static var LinterModules linterModules; -:379: static function addLinterModule(s8[] value): bool -:380: { 10:381: if value == "all" do -:382: { 1:383: linterModules = linterModules.max; 1:384: return false; -:385: } -:386: 9:387: var bool include = true; 9:388: if value[0] == "-" do -:389: { 1:390: value = value[1 .. value.length]; 1:391: include = false; -:392: } 8:393: else do if value[0] == "+" do -:394: { 3:395: value = value[1 .. value.length]; 3:396: include = true; -:397: } 27:398: switch value do -:399: { 1:400: on "suggestOptAssign" do linterModules[suggestOptAss] = include; 1:401: on "suggestCondExp" do linterModules[suggestCondExp] = include; 1:402: on "suggestBreakExp" do linterModules[suggestBreakExp] = include; 0:403: on "suggestCondToLogical" do linterModules[suggestCondToLogical] = include; 2:404: on "unusedLocals" do linterModules[unusedLocals] = include; 1:405: on "unusedImports" do linterModules[unusedImports] = include; 1:406: on "assignInAssert" do linterModules[assignInAssert] = include; 0:407: on "reslice" do linterModules[reslice] = include; 1:408: on "loopInvariant" do linterModules[loopInvariant] = include; 1:409: else do return printMessageAndReturnTrue(("invalid linter module, use `all` to activate all and not `" ~ value ~ "`\0").ptr); -:410: } 8:411: return false; -:412: } -:413: -:414:// --------------------- -:415: -:416: static var u32 ptr_size; -:417: static function setRegSize(s8[] value): bool -:418: { 4:419: if value == "32" do 2:420: ptr_size = 32; 2:421: else do if value == "64" do 1:422: ptr_size = 64; -:423: else do 1:424: return printMessageAndReturnTrue(("invalid memory model, `32` or `64` expected, not `" ~ value ~ "`\0").ptr); 3:425: return false; -:426: } -:427: -:428:// --------------------- -:429: -:430: static var u8 optLevel; -:431: static function setOptLevel(s8[] value): bool -:432: { 6:433: const auto c = value[0]; 6:434: if value.length == 1 && "0" <= c && c <= "3" do -:435: { 5:436: optLevel = c - "0"; 5:437: return false; -:438: } 1:439: else do return printMessageAndReturnTrue(("invalid optimization level, `0`, `1`, `2`, or `3` expected, not `" ~ value ~ "`\0").ptr); -:440: } -:441: -:442:// --------------------- -:443: -:444: /// if `@unittest` functions are compiled -:445: static var bool compileUnittest; -:446: static function setCompileUnittest(bool value): bool -:447: { 8:448: compileUnittest = value; 8:449: if value do -:450: { 8:451: additionalChecks += asserts; 8:452: versions ~="unittest"; -:453: } 8:454: return false; -:455: } -:456: -:457:// --------------------- -:458: -:459: /// Indicates how warnings are handled. -:460: static var WarningType warningType; -:461: static function setWarningType(s8[] value): bool -:462: { 12:463: switch value do -:464: { 2:465: on "error" do warningType = WarningType.error; 0:466: on "enabled" do warningType = WarningType.enabled; 1:467: on "disabled" do warningType = WarningType.disabled; 1:468: else do return printMessageAndReturnTrue(("invalid `-w` argument, `enabled`, `disabled`, or `error` expected, not `" ~ value ~ "`\0").ptr); -:469: } 3:470: return false; -:471: } -:472: -:473:// --------------------- -:474: -:475: /// Indicates how deprecations are handled. -:476: static var WarningType deprecationType; -:477: static function setDeprecationType(s8[] value): bool -:478: { 15:479: switch value do -:480: { 2:481: on "error" do deprecationType = WarningType.error; 1:482: on "enabled" do deprecationType = WarningType.enabled; 1:483: on "disabled" do deprecationType = WarningType.disabled; 1:484: else do return printMessageAndReturnTrue(("invalid `-d` argument, `enabled`, `disabled`, or `error` expected, not `" ~ value ~ "`\0").ptr); -:485: } 4:486: return false; -:487: } -:488: -:489:// --------------------- -:490: -:491: /// Indicates what the backend produces. -:492: static var BackendOutputKind beKind; -:493: static function setBeKind(s8[] value): bool -:494: { 120:495: switch value do -:496: { 26:497: on "ir" do beKind = BackendOutputKind.ir; 2:498: on "bc" do beKind = BackendOutputKind.bc; 2:499: on "ar" do beKind = BackendOutputKind.ar; 0:500: on "exe" do beKind = BackendOutputKind.exe; 8:501: on "obj" do beKind = BackendOutputKind.obj; 1:502: on "asm" do beKind = BackendOutputKind.$asm; 1:503: else do return printMessageAndReturnTrue(("invalid `--be` argument, `exe`, `obj`, `ar`, `asm`, `bc`, or `ir` expected, not `" ~ value ~ "`\0").ptr); -:504: } 39:505: return false; -:506: } -:507: -:508:// --------------------- -:509: -:510: /// custom linkers flags -:511: static var s8[][+] additionalLinkerArgs; -:512: static function addLinkerArg(s8[] value): bool -:513: { 1:514: additionalLinkerArgs ~= value; 1:515: return false; -:516: } -:517: -:518:// --------------------- -:519: -:520: /// Indicates if errors happened. 1465:521: static function hasErrors(): bool {return _errorsCount != 0;} -:522: -:523: /// Sets if messages are gagged. -:524: static function startGagging(): usize -:525: { 13811:526: _gag++; 13811:527: return _gaggedErrorCount; -:528: } -:529: -:530: /// Sets if messages are gagged. -:531: static function stopGagging(): usize -:532: { 13811:533: _gag > 0 ? _gag-- else _gag = 0; 13811:534: return _gaggedErrorCount; -:535: } -:536: -:537: /// Temporarily stop gagging -:538: static function pauseGagging(): usize -:539: { 58962:540: const usize result = _gag; 58962:541: _gag = 0; 58962:542: return result; -:543: } -:544: -:545: /// Resume gagging -:546: static function resumeGagging(const usize pauseValue) -:547: { 58962:548: _gag = pauseValue; 58962:549: } -:550: -:551: /// Returns: The count of error. 2840:552: static function errorsCount(): usize {return _errorsCount;} -:553: -:554: /// -:555: static function defaultMessageFunc(MessageType type; s8[+] filename; Position pos; s8* spec; va_list* va) -:556: { 2451:557: static const s8*[MessageType.max + 1] typeStr = ["error", "information", "warning", "deprecation"]; 2451:558: filename ~= 0; 2451:559: printf("%s:%d:%d: %s, ", filename.ptr, pos.line, pos.column, typeStr[type]); 2451:560: vprintf(spec, va); 2451:561: printf("\n"); 2451:562: } -:563: -:564: /** -:565: * Adds an error message. -:566: * -:567: * Params: -:568: * filename = The file where the error is located. -:569: * pos = The error position. -:570: * spec = A format specifier. -:571: * ... = The variadic arguments, as expected by the specifier. -:572: */ -:573: static function error(const s8[] filename; Position pos; s8* spec; ...) -:574: { 3794:575: if _gag do -:576: { 1435:577: _gaggedErrorCount++; 1435:578: return; -:579: } -:580: 2359:581: _errorsCount++; 2359:582: if !messageFunc do 1:583: return; -:584: -:585: var va_list lst; 2358:586: var u8* va = (&lst):u8*; 2358:587: va_start(va); 2358:588: messageFunc(MessageType.error, filename, pos, spec, &lst); 2358:589: va_end(va); 2358:590: } -:591: -:592: /** -:593: * Adds an informational message. -:594: * -:595: * Params: -:596: * filename = The file where the error is located. -:597: * pos = The error position. -:598: * spec = A format specifier. -:599: * ... = The variadic arguments, as expected by the specifier. -:600: */ -:601: version none do static function info(const s8[] filename; Position pos; s8* spec; ...) -:602: { -:603: if _gag do -:604: return; -:605: -:606: if !messageFunc do -:607: return; -:608: -:609: var va_list lst; -:610: var u8* va = (&lst):u8*; -:611: va_start(va); -:612: messageFunc(MessageType.info, filename, pos, spec, &lst); -:613: va_end(va); -:614: } -:615: -:616: /** -:617: * Adds an warning message. -:618: * -:619: * Params: -:620: * filename = The file where the error is located. -:621: * pos = The error position. -:622: * spec = A format specifier. -:623: * ... = The variadic arguments, as expected by the specifier. -:624: */ -:625: static function warn(const s8[] filename; Position pos; s8* spec; ...) -:626: { 95:627: if _gag do 0:628: return; -:629: 95:630: if warningType == WarningType.disabled do 1:631: return; 94:632: if warningType == WarningType.error do 29:633: _errorsCount++; -:634: 94:635: if !messageFunc do 1:636: return; -:637: -:638: var va_list lst; 93:639: var u8* va = (&lst):u8*; 93:640: va_start(va); 93:641: messageFunc(MessageType.warn, filename, pos, spec, &lst); 93:642: va_end(va); 93:643: } -:644: -:645: /** -:646: * Adds a deprecation message. -:647: * -:648: * Params: -:649: * filename = The file where the error is located. -:650: * pos = The error position. -:651: * spec = A format specifier. -:652: * ... = The variadic arguments, as expected by the specifier. -:653: */ -:654: static function deprecation(const s8[] filename; Position pos; s8* spec; ...) -:655: { 1:656: if _gag do 0:657: return; -:658: 1:659: if deprecationType == WarningType.disabled do 0:660: return; 1:661: if deprecationType == WarningType.error do 0:662: _errorsCount++; -:663: 1:664: if !messageFunc do 1:665: return; -:666: -:667: var va_list lst; 0:668: var u8* va = (&lst):u8*; 0:669: va_start(va); 0:670: messageFunc(MessageType.dep, filename, pos, spec, &lst); 0:671: va_end(va); 0:672: } -:673:} -:674: -:675:alias session = Session; <<<<<< EOF # path=src/styx/string_switch.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/string_switch.sx -: 1:/* Lookup table used to switch over string literals */ -: 2:unit styx.string_switch; -: 3: -: 4:struct StringSwitchData -: 5:{ -: 6: alias Table = u8[+]; -: 7: var s8[][+] words; -: 8: var Table table; -: 9: var u8 minChar = u8.max; -: 10: var u8 maxChar = u8.min; -: 11: var usize minLen = usize.max; -: 12: var usize maxLen = usize.min; -: 13: -: 14: // a column entry maps a character to the column where to read the next character -: 15: var usize numCols; -: 16: // first row contains the result, i.e the original index (1-based) in the words -: 17: var usize numRows; -: 18: -: 19: /* example table for the words "BAD", "CAB", and "BAC" -: 20: -: 21: | C0 C1 C2 C3 C4 -: 22: ------------------------ -: 23: R0 | 0 1 2 3 0 -: 24: R1 'A' | 0 2 0 4 0 -: 25: R2 'B' | 1 0 0 0 2 -: 26: R3 'C' | 3 0 3 0 0 -: 27: R4 'D' | 0 0 1 0 0 -: 28: -: 29: BAD : column 0, line B -> read next in column 1 -: 30: column 1, line A -> read next in column 2 -: 31: column 2, line D -> read next in column 1, there's no next, index of BAD is in column 1 of row 0 -> 1 -: 32: CAB : column 0, line C -> read next in column 3 -: 33: column 3, line A -> read next in column 4 -: 34: column 4, line B -> read next in column 2, there's no next, index of CAB is in colmun 2 of row 0 -> 2 -: 35: BAC : column 0, line B -> read next in column 1 -: 36: column 1, line A -> read next in column 2 -: 37: column 2, line C -> read next in column 3, there's no next, index of BAC is in column 3 of row 0 -> 3 -: 38: BABE: colmun 0, line B -> read next in column 1 -: 39: column 1, line A -> read next in column 2 -: 40: column 2, line B -> read next in column 0, which is never used to store an index, meaning BABE is not in the table -: 41: */ -: 42: -: 43: @destructor function destroy() -: 44: { 0: 45: words.decref; 0: 46: table.decref; 0: 47: } -: 48: -: 49: function appendWord(s8[] word) -: 50: { 489: 51: assert(!table.length); 489: 52: const auto wlen = word.length; 810: 53: if wlen > maxLen do maxLen = wlen; 522: 54: if wlen < minLen do minLen = wlen; 489: 55: foreach const auto c in word do -: 56: { 34100: 57: if c:u8 > maxChar do maxChar = c:u8; 34095: 58: if c:u8 < minChar do minChar = c:u8; -: 59: } -: 60: // sort by length, required for sets containing words with a common prefix 489: 61: if !words.length do 19: 62: words ~= word; -: 63: else do -: 64: { 470: 65: var usize j = words.length; 470: 66: foreach (const auto i; const auto w) in words do -: 67: { 34414: 68: if w.length > wlen do 148: 69: break j = i; 34266: 70: else do if w.length < wlen do 33747: 71: j = i + 1; -: 72: } 470: 73: words.length += 1; 470: 74: words[j + 1 .. $] = words[j .. $ - 1]; 470: 75: words[j] = word; -: 76: } 489: 77: } -: 78: -: 79: function unique(): bool -: 80: { 18: 81: foreach (const auto wi; const auto w0) in words do 231: 82: foreach (var auto w1) in words[wi+1 .. $] do 3505: 83: if w1 == w0 do 1: 84: return false; 17: 85: return true; -: 86: } -: 87: -: 88: function prepareLut() -: 89: { 249: 90: if table.length do 232: 91: return; -: 92: 17: 93: numRows = (2 + maxChar) - minChar; 17: 94: numCols = getColumnsCount(); 17: 95: table.length = numRows * numCols; 17: 96: var u8 numInserts = 1; 17: 97: foreach (const auto wi; const auto w) in words do -: 98: { -: 99: var u16 nextPos; 230:100: foreach (const auto ci; const auto c) in w do -:101: { 1390:102: if ci != w.length -1 do -:103: { 1160:104: nextPos = table[(1 + c:u8 - minChar) * numCols + nextPos] ?= numInserts++; -:105: } -:106: else do -:107: { 230:108: table[(1 + c:u8 - minChar) * numCols + nextPos] ?= (wi + 1):u8; 230:109: table[wi + 1] = (wi + 1):u8; -:110: } -:111: } -:112: } 17:113: } -:114: -:115: /// Returns: the index from which current content forks from prev -:116: static function forkFrom(s8[] current; s8[] prev): usize -:117: { -:118: var usize result; 3504:119: foreach (const auto charIndex; const auto char) in current do -:120: { 5194:121: if charIndex >= prev.length do 149:122: break; 5045:123: if char == prev[charIndex] do 1690:124: result++; 3355:125: else do break; -:126: } 3504:127: return result; -:128: } -:129: -:130: /// Returns: the number of columns required to store the words -:131: function getColumnsCount(): auto -:132: { -:133: // at least one column 17:134: var usize result = 1; -:135: // fixed num of col for the 1st word 17:136: result += words[0].length - 1; 17:137: foreach (const auto insertedWordIndex; const auto insertedWord) in words do -:138: { 230:139: if insertedWordIndex == 0 do 17:140: continue; 213:141: var usize ffMax = 0; -:142: // remainings words: add the count of chars, minus the length of the prefix that's common with what's already been stored 213:143: foreach (var auto prevWord) in words[0 .. insertedWordIndex] do -:144: { 3504:145: var auto ff = forkFrom(insertedWord, prevWord); 3504:146: ffMax = ff > ffMax ? ff else ffMax; 3504:147: ffMax = ffMax > insertedWord.length-1 ? insertedWord.length-1 else ffMax; -:148: } 213:149: result += insertedWord[ffMax .. $-1].length; -:150: } 17:151: return result < words.length + 1 ? words.length + 1 else result; -:152: } -:153: -:154: function getLutIndex(s8[] word): s32 -:155: { -:156: var s32 nextPos; 232:157: prepareLut(); 232:158: if word.length < minLen || word.length > maxLen do 1:159: return 0; 231:160: foreach (const auto ci; const auto c) in word do -:161: { 1394:162: if c:u8 < minChar || c:u8 > maxChar do 0:163: return 0; 1394:164: nextPos = table[((1 + c:u8 - minChar) * numCols) + nextPos]; 1394:165: if nextPos == 0 do 0:166: return 0; 1394:167: if ci + 1 == word.length && table[nextPos] && words[table[nextPos] - 1] == word do 231:168: return table[nextPos]; -:169: } 0:170: return 0; -:171: } -:172:} <<<<<< EOF # path=src/styx/symbol.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/symbol.sx -: 1:unit styx.symbol; -: 2: -: 3:@private import -: 4: system, -: 5: styx.session, -: 6: styx.position, -: 7: styx.token, -: 8: styx.ast.base, -: 9: styx.ast.declarations, -: 10: ; -: 11: -: 12:/// Enumerates the possible kinds of symbols -: 13:enum SymbolKind : u16 -: 14:{ -: 15: unamed, -: 16: $label, -: 17: $alias, -: 18: $import, -: 19: $function, -: 20: unitDot, -: 21: $unit, -: 22: variable, -: 23: $enum, -: 24: $enumMember, -: 25: $class, -: 26: $struct, -: 27: $union, -: 28: $overload, -: 29: genericParameter, -: 30: expAlias, -: 31:} -: 32: -: 33:/// Set of SymbolKind -: 34:alias SymbolKinds = bool[SymbolKind]; -: 35: -: 36:/// Constant set of symbol kinds containing all the unit kinds. -: 37:const SymbolKinds unitKinds = [$unit, unitDot]; -: 38:const SymbolKinds unitOrImportKinds = [$unit, unitDot, $import]; -: 39: -: 40:/// Constant set of symbol kinds containing all the aggregates kinds. -: 41:const SymbolKinds aggregateKinds = [$class, $struct, $union]; -: 42: -: 43:const SymbolKinds needScopeKinds = [$class, $struct, $union, $function, $unit, $unitDot, $enum]; -: 44: -: 45:const SymbolKinds localForeignKinds = [$struct, $union, $function, variable]; -: 46: -: 47:/// Returns: If the argument is for an `AggregateDeclaration`, this `AggregateDeclaration` else `null` -: 48:function symToAggrDecl(Symbol* s): AggregateDeclaration* -: 49:{ 5694: 50: return s.kind in aggregateKinds ? *((&s.astNode):AggregateDeclaration**) else null; -: 51:} -: 52: -: 53:/// Returns: If the argument is for an `AliasDeclaration`, this `AliasDeclaration` else `null` -: 54:function symToAliasDecl(Symbol* s): AliasDeclaration* -: 55:{ 65424: 56: return s?.kind == $alias ? *((&s.astNode):AliasDeclaration**) else null; -: 57:} -: 58: -: 59:/// Returns: If the argument is for an `EnumDeclaration`, this `EnumDeclaration` else `null` -: 60:function symToEnumDecl(Symbol* s): EnumDeclaration* -: 61:{ 17687: 62: return s?.kind == $enum ? *((&s.astNode):EnumDeclaration**) else null; -: 63:} -: 64: -: 65:/// Returns: If the argument is for an `EnumMember`, this `EnumMember` else `null` -: 66:function symToEnumMember(Symbol* s): EnumMember* -: 67:{ 33801: 68: return s?.kind == enumMember ? *((&s.astNode):EnumMember**) else null; -: 69:} -: 70: -: 71:/// Returns: If the argument is for a `FunctionDeclaration`, this `FunctionDeclaration` else `null` -: 72:function symToFuncDecl(Symbol* s): FunctionDeclaration* -: 73:{ 181968: 74: return s?.kind == $function ? *((&s.astNode):FunctionDeclaration**) else null; -: 75:} -: 76: -: 77:/// Returns: If the argument is for an `GenericParameter`, this `GenericParameter` else `null` -: 78:function symToGenericParam(Symbol* s): GenericParameter* -: 79:{ 14832: 80: return s?.kind == genericParameter ? *((&s.astNode):GenericParameter**) else null; -: 81:} -: 82: -: 83:/// Returns: If the argument is for an `ExpressionAlias`, this `ExpressionAlias` else `null` -: 84:function symToExpAlias(Symbol* s): ExpressionAlias* -: 85:{ 21640: 86: return s?.kind == expAlias ? *((&s.astNode):ExpressionAlias**) else null; -: 87:} -: 88: -: 89:/// Returns: If the argument is an `ImportElement`, this `ImportElement` else `null` -: 90:function asImportElement(Symbol* s): ImportElement* -: 91:{ 235898: 92: return s.kind == $import ? *((&s):ImportElement**) else null; -: 93:} -: 94: -: 95:/// Returns: If the argument is for an `OverloadDeclaration`, this `OverloadDeclaration` else `null` -: 96:function symToOverDecl(Symbol* s): OverloadDeclaration* -: 97:{ 114858: 98: return s?.kind == $overload ? *((&s.astNode):OverloadDeclaration**) else null; -: 99:} -:100: -:101:/// Returns: If the argument is for a `VarDeclaration`, this `VarDeclaration` else `null` -:102:function symToVarDecl(Symbol* s): VariableDeclaration* -:103:{ 622484:104: return s?.kind == variable ? *((&s.astNode):VariableDeclaration**) else null; -:105:} -:106: -:107:class Symbol -:108:{ -:109: /// The symbol name -:110: var Token* name; -:111: /// The symbol parent -:112: var Symbol* parent; -:113: /// The symbol children -:114: var Symbol*[+] children; -:115: /// The symbol children -:116: var Symbol*[+] importCache; -:117: /// The matching AST node. -:118: var AstNode* astNode; -:119: /// So that searchWild & searchStrict can return TypeDeclared.declaration -:120: var Type* type; -:121: /// The symbol kind -:122: var SymbolKind kind; -:123: /// Flag used to prevent cases of infinite recursions. -:124: var u8 recurseGuard; -:125: /// -:126: static var Symbol* beingInit; -:127: -:128: /// Constructs a new symbol and adds it to `parent` children. -:129: @constructor function create(Token* name; Symbol* parent; SymbolKind kind) -:130: { 30415:131: this.name = name; 30415:132: this.parent = parent; 30415:133: this.kind = kind; 30415:134: if parent do -:135: { 30415:136: parent.children ~= this; 30415:137: if kind == $import do 1128:138: parent.importCache ~= this; -:139: } 30415:140: } -:141: -:142: /// Constructs a new unamed Symbol, e.g for the decls located in a BlockStatement -:143: @constructor function createUnamed(Symbol* parent) -:144: { -:145: static var u32 cnt; 15993:146: this.name = u32ToString(cnt++).identifier(); 15993:147: this.parent = parent; 15993:148: this.kind = SymbolKind.unamed; 31261:149: if parent do parent.children ~= this; 15993:150: } -:151: -:152: /// -:153: @virtual @destructor function destroy() -:154: { -:155: // for statements syms 644:156: if kind == unamed do 483:157: delete name; -:158: 644:159: foreach var auto c in children do 268:160: delete c; 644:161: children.decref; 644:162: importCache.decref; 644:163: } -:164: -:165: function flagAsBeingInit(bool start) -:166: { 8604:167: beingInit = start ? this else null; 8604:168: } -:169: -:170: /// Returns: the fully qualified name. -:171: function fqn(bool includeUnit): Token*[+] -:172: { -:173: var Token*[+] result; 7277:174: var auto c = this; 7277:175: var auto r = Root.instance():u8*; 7277:176: while true do -:177: { 22663:178: result = c.name ~ result; 22663:179: c = c.parent; 22663:180: if !includeUnit && c.kind == $unit do 5:181: break; 22658:182: if includeUnit && c && c:u8* == r do 7272:183: break; -:184: } 7277:185: return result; -:186: } -:187: -:188: /// Returns: the aggregate where this symbol is declared. -:189: function parentAggregate(): Symbol* -:190: { 42924:191: var auto current = parent; 42924:192: while current do -:193: { 77284:194: if current.kind in aggregateKinds do 31925:195: return current; 45359:196: current = current.parent; -:197: } 10999:198: return null; -:199: } -:200: -:201: /// Returns: the symbol as type, e.g TypeStruct if the symbol is created for a StructDeclaration -:202: function asType(): Type* -:203: { 60961:204: switch kind do -:205: { -:206: on $class, $enum, $function, $struct, $union, $overload, genericParameter 50137:207: do return (*((&astNode):Declaration**)).asTypeDeclared; -:208: else 10824:209: do return null; -:210: } -:211: } -:212: -:213: /** -:214: * Returns: $(D true) if this symbol is visible from $(D loc), $(D false) -:215: * otherwise. -:216: */ -:217: function isVisibleFrom(Symbol* loc): bool -:218: { 65632:219: if parent:u8* == loc:u8* do 13862:220: return true; -:221: // same unit, only strict inner decl are invisible 51770:222: if parentUnit():u8* == loc.parentUnit():u8* do -:223: { 33962:224: var auto d = astNode.asDeclaration(); 33962:225: return !(d && d.$protection == strict) || parentAggregate() == loc.parentAggregate(); -:226: } -:227: else do -:228: { -:229: // import 35616:230: if var auto ie = asImportElement(this) do 5:231: if ie.$protection != Protection.public do 5:232: return false; -:233: 17803:234: var auto s = this; 17803:235: const auto symParentAggr = loc.parentAggregate(); 17803:236: const auto thisParentAggr = s.parentAggregate(); 17803:237: const auto locParentAggr = symParentAggr ? *((&symParentAggr.astNode):AggregateDeclaration**) else null; -:238: -:239: var bool needInheritance; 17803:240: const auto r = Root.instance():u8*; 17803:241: while s.parent:u8* != r do -:242: { 30097:243: var auto d = s.astNode.asDeclaration(); 30097:244: if !d do 0:245: return true; 30097:246: if needInheritance && locParentAggr && thisParentAggr do -:247: { 2:248: foreach var auto tan in locParentAggr.inheritanceList do 1:249: if tan.resolved():u8* == thisParentAggr.type.resolved():u8* do 1:250: return true; -:251: } 30096:252: switch d.$protection do -:253: { 6:254: on Protection.private do return false; -:255: on Protection.protected do -:256: { 3:257: needInheritance = true; 3:258: if s.parent.astNode:u8* == s.parentUnit():u8* || !s.parent do 1:259: return false; 2:260: continue s = s.parent; -:261: } -:262: on Protection.public do -:263: { 30087:264: if s.parent.astNode:u8* == s.parentUnit():u8* || !s.parent do 17793:265: return !needInheritance; 12294:266: continue s = s.parent; -:267: } 0:268: else do return false; -:269: } -:270: } 2:271: return true; -:272: } -:273: } -:274: -:275: /** -:276: * Finds direct children. -:277: * -:278: * Params: -:279: * name = The symbol name, either as a string or as a $(D Token*). -:280: * kind = The symbol kind. -:281: * -:282: * Returns: On success the symbol, $(D null) otherwise. -:283: */ -:284: function findChildOfKind(Token* name; const SymbolKind kind): Symbol* -:285: { 1293:286: foreach const Symbol* c in children do 2157:287: if c.name && c.kind == kind && c.name.iptr() == name.iptr() do 761:288: return c; 532:289: return null; -:290: } -:291: -:292: /** -:293: * Finds direct children. -:294: * -:295: * Params: -:296: * name = The symbol name, either as a string or as a $(D Token*). -:297: * kinds = The symbol kinds. -:298: * -:299: * Returns: On success the symbol, $(D null) otherwise. -:300: */ -:301: function findChildInKinds(Token* name; SymbolKinds kinds = 0): Symbol* -:302: { 49005:303: if kinds == 0 do -:304: { 47559:305: foreach const Symbol* c in children do 242722:306: if c.name && c.name.iptr() == name.iptr() do 383:307: return c; -:308: } -:309: else do -:310: { 1446:311: foreach const Symbol* c in children do 3302:312: if c.name && (c.kind in kinds) && c.name.iptr() == name.iptr() do 907:313: return c; -:314: } 47715:315: return null; -:316: } -:317: -:318: overload find {findChildOfKind, findChildInKinds} -:319: -:320: /** -:321: * Searches for a named symbol in this scope, exluding parents scopes unless they -:322: * are BlockStatement. Used when solving dotted TypeIdentifierPath or dotted expressions. -:323: * -:324: * Params: -:325: * targetName = The name of the symbol to search. -:326: * targetPos = Indicates the position where the name is used. -:327: * targetScope = Indicates the scope where the name is used (for protection check). -:328: * Returns: -:329: * A `Symbol` on success, `null` otherwise. `getAliasee` should be called -:330: * on the result if its kind is `alias` -:331: */ -:332: function searchStrict(Token* targetName; const var Position targetPos; Symbol* targetScope): Symbol* -:333: { -:334: //printf("`%d: searchStrict` with scope `%s` of kind `%d`, looking for `%s`\n", -:335: // name ? name.text().ptr else "(unamed)", kind, targetName.text().ptr); -:336: 32384:337: foreach const auto s in children do -:338: { 792949:339: if !s.name || s.name.iptr() != targetName.iptr() || s:u8* == beingInit:u8* do 776423:340: continue; -:341: // search is strict. Issue an error if result is not visible. 16526:342: if !s.isVisibleFrom(targetScope) do -:343: { 10:344: var auto ud = targetScope.parentUnit(); 10:345: session.error(ud.filename, targetPos, "symbol `%s` is not visible from here", s.name.text().ptr); 10:346: return null; -:347: } -:348: // match but `s` is an import, extract the unit `Symbol` 33032:349: if var auto ie = asImportElement(s) do -:350: { 34:351: if var auto tu = ie.terminalUnit do 14:352: return tu; -:353: // prevent symbol leaks, nothing will be found if it's not a terminalUnit 3:354: return ie; -:355: } -:356: // match, no special case 16499:357: return s; -:358: } 15858:359: switch kind do -:360: { -:361: on unamed do assert(0, "searchStrict() in a block statement"); -:362: // try in the inherited types -:363: on $class do -:364: { 14165:365: var auto cd = *((&astNode):ClassDeclaration**); 14165:366: foreach var auto t in cd.inheritanceList do 18904:367: if var auto s = t.asSymbol() do -:368: { 9451:369: if s.name.iptr() == targetName.iptr() do 68:370: return s; 9383:371: if (s = s.searchStrict(targetName, targetPos, targetScope)) do 4063:372: return s; -:373: } -:374: } -:375: on $enum do -:376: { 1632:377: var auto ed = *((&astNode):EnumDeclaration**); 1632:378: if ed.base do 1596:379: return ed.base.asSymbol().searchStrict(targetName, targetPos, targetScope); -:380: } 61:381: else do {} -:382: } 10131:383: return null; -:384: } -:385: -:386: /** -:387: * Searches for a named symbol from this scope, descending in the parents scopes. -:388: * Used to solve first `TypeIdentifierPart` of chains or the first expression -:389: * of possibly nested `DotExpression`s. -:390: * -:391: * Params: -:392: * targetName = The name of the symbol to search. -:393: * targetPos = Indicates the position where the name is used. -:394: * targetScope = Indicates the scope where the name is used (for protection check). -:395: * Returns: -:396: * A `Symbol` on success, `null` otherwise. `getAliasee` should be called -:397: * on the result if its kind is `alias` -:398: */ -:399: function searchWild(Token* targetName; const var Position targetPos; Symbol* targetScope): Symbol* -:400: { -:401: //printf("%d: `searchWild` with scope `%s` of kind `%d`, looking for `%s`\n", -:402: // name ? name.text().ptr else "(unamed)", kind, targetName.text().ptr); -:403: -:404: static function isLocalScopeRespected(Symbol* s; const var Position declPos; const var Position usePos; Symbol* targetScope): bool -:405: { 18582:406: var AstNode* u1 = targetScope.parentUnit(); 18582:407: var AstNode* u2 = s.parentUnit(); 18582:408: return u1:u8* != u2:u8* || usePos > declPos; -:409: } -:410: 220499:411: foreach const auto s in children do -:412: { 4101223:413: if s:u8* == beingInit:u8* do continue; -:414: // exact match in the scope 4090569:415: if s.name && s.name.iptr() == targetName.iptr() do -:416: { -:417: // wild search is, dont issue an error if result is not visible -:418: // it is simply something else that's required 48852:419: if !s.isVisibleFrom(targetScope) do 10:420: continue; -:421: // match is an import, extract the unit `Symbol` 97684:422: if var auto ie = asImportElement(s) do -:423: { 114:424: if var auto tu = ie.terminalUnit do -:425: { 43:426: if kind == unamed && !isLocalScopeRespected(this, ie.startPos, targetPos, targetScope) do 0:427: continue; 43:428: return tu; -:429: } -:430: // prevent symbol leaks, nothing will be found if it's not a terminalUnit 14:431: return ie; -:432: } -:433: // match, no special case 48785:434: if kind != unamed || isLocalScopeRespected(this, s.astNode.startPos, targetPos, targetScope) do 48782:435: return s; -:436: } -:437: } -:438: // try in the inherited types 171660:439: if kind == SymbolKind.$class do -:440: { 5626:441: var auto cd = *((&astNode):ClassDeclaration**); 5626:442: foreach var auto t in cd.inheritanceList do 11090:443: if var auto s = t.asSymbol() do -:444: { 5209:445: if (s = s.searchStrict(targetName, targetPos, targetScope)) do 597:446: return s; -:447: } -:448: } -:449: // try the imports declared in this scope, e.g unqualified use of imported symbol 171063:450: const auto inSubScope = kind == unamed; 171063:451: foreach const auto s in importCache do -:452: { 152732:453: const auto i = asImportElement(s); 152732:454: if i.forSelfStrictSearch || !i.canBeSeenFrom(targetScope) do 106437:455: continue; 46295:456: var auto selected = true; 92590:457: if const auto slen = i.selection.length do -:458: { 16:459: selected = false; 16:460: foreach var auto sel in i.selection.ptr[0 .. slen] do 16:461: if sel.iptr() == targetName.iptr() do 3:462: break selected = true; -:463: } 92577:464: if selected do foreach const auto ie in i.nonQualified do -:465: { 74999:466: if inSubScope && !isLocalScopeRespected(this, ie.startPos, targetPos, targetScope) do 104:467: continue; 74895:468: var auto ss = ie.terminalUnit ? ie; 149790:469: if var auto us = ss.searchWild(targetName, targetPos, targetScope) do 5288:470: return us; -:471: } -:472: } -:473: // dig in the parent scopes 165775:474: var auto p = parent; 165775:475: if p:u8* != Root.instance():u8* && -:476: // eventually until current unit but not its parent unit 126342:477: !(p.kind in unitKinds && kind in unitKinds) do 94840:478: return p.searchWild(targetName, targetPos, targetScope); -:479: 70935:480: return null; -:481: } -:482: /// -:483: function parentUnit(): UnitDeclaration* -:484: { 922444:485: if kind == $unit do 334689:486: return *((&astNode):UnitDeclaration**); 587755:487: return parent.parentUnit(); -:488: } -:489:} -:490: -:491:/** -:492: * used to make a tree of the imports and prevent symbol leaks. -:493: * Symbol leaks would happen if imported unit was put as is in the main tree, e.g -:494: * with `import a.b.c;` `a.member` could leak with a `searchWild()` */ -:495:@final class ImportElement : Symbol -:496:{ -:497: /** Not null if this element is the end of a chain or the end -:498: * of a shorter import chain */ -:499: var Symbol* terminalUnit; -:500: /** Stores all the inner elements that have a terminal unit, -:501: * simplifying unqualified searches. Only defined for a root unit */ -:502: var ImportElement*[+] nonQualified; -:503: /// The position of the matching ImportDeclaration -:504: var Position startPos; -:505: /// A copy of protection of the original ImportDeclaration, as astNode gives a TypeIdentifier -:506: var Protection $protection; -:507: /// Symbols that `searchWild()` are allowed to find -:508: var Token*[+] selection; -:509: /// only used to perform qualified searches in curr unit -:510: var bool forSelfStrictSearch; -:511: /// -:512: @constructor function create(Token* name; Symbol* parent; Symbol* terminalUnit; const bool forSelfStrictSearch = false) -:513: { 1128:514: super.create(name, parent, SymbolKind.$import); 1128:515: this.terminalUnit = terminalUnit; 1128:516: this.forSelfStrictSearch = forSelfStrictSearch; 1128:517: } -:518: /// -:519: @override @destructor function destroy() -:520: { 5:521: nonQualified.decref; 5:522: selection.decref; 5:523: super(); 5:524: } -:525: /// -:526: function canBeSeenFrom(Symbol* loc): bool -:527: { 81797:528: if parent:u8* == loc:u8* do 224:529: return true; 81573:530: if parentUnit():u8* == loc.parentUnit():u8* do 14336:531: return $protection != Protection.strict || parentAggregate() == loc.parentAggregate(); 67237:532: return $protection == Protection.public; -:533: } -:534:} -:535: -:536:/** Manage the root symbol -:537: -:538:The root symbol own the whole tree of symbols. -:539:It contains the top level structures, i.e the units and -:540:allow to detect when a "wild" search fails */ -:541:struct Root -:542:{ -:543:protection (private) -:544: -:545: @constructor static function staticCtor() -:546: { 374:547: i = (new Symbol).createUnamed(null); 374:548: } -:549: -:550: @constructor static function staticDtor() -:551: { 374:552: delete i; 374:553: } -:554: -:555: static var Symbol* i; -:556: -:557:protection (public) -:558: -:559: /// -:560: static function instance(): Symbol* -:561: { 191794:562: return i ? i = (new Symbol).createUnamed(null); -:563: } -:564: -:565: /// For @unittest -:566: static function reset() -:567: { 2:568: delete i; 2:569: i = null; 2:570: } -:571:} <<<<<< EOF # path=src/styx/token.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/token.sx -: 1:/** -: 2: * The Styx token type, as produced by the lexer. -: 3: * Also contains a static hash map used to match the keywords. -: 4: */ -: 5:unit styx.token; -: 6: -: 7:@private import -: 8: system, -: 9: styx.position, -: 10: ; -: 11: -: 12:/// Enumerates the different token. -: 13:enum TokenType : u8 -: 14:{ -: 15: invalid, -: 16: eof, -: 17: id, -: 18: // -: 19: intLiteral, -: 20: floatLiteral, -: 21: hexLiteral, -: 22: binLiteral, -: 23: stringLiteral, -: 24: rawStringLiteral, -: 25: // -: 26: lineComment, -: 27: starComment, -: 28: // Keywords -: 29: $alias, -: 30: $apply, -: 31: $assert, -: 32: $asm, -: 33: $auto, -: 34: $break, -: 35: $class, -: 36: $const, -: 37: $continue, -: 38: $delete, -: 39: $do, -: 40: $echo, -: 41: $else, -: 42: $enum, -: 43: $false, -: 44: $foreach, -: 45: $function, -: 46: $goto, -: 47: $if, -: 48: $import, -: 49: $in, -: 50: $label, -: 51: $new, -: 52: $null, -: 53: $on, -: 54: $overload, -: 55: $protection, -: 56: $return, -: 57: $static, -: 58: $struct, -: 59: $super, -: 60: $switch, -: 61: $this, -: 62: $true, -: 63: $union, -: 64: $unit, -: 65: $var, -: 66: $version, -: 67: $with, -: 68: $while, -: 69: // basic types -: 70: $bool, -: 71: $f32, -: 72: $f64, -: 73: $s16, -: 74: $s32, -: 75: $s64, -: 76: $s8, -: 77: $ssize, -: 78: $u16, -: 79: $u32, -: 80: $u64, -: 81: $u8, -: 82: $usize, -: 83: // symbols -: 84: not, -: 85: qmark, -: 86: colon, -: 87: comma, -: 88: dot, -: 89: semiColon, -: 90: leftCurly, -: 91: leftParen, -: 92: leftSquare, -: 93: rightCurly, -: 94: rightParen, -: 95: rightSquare, -: 96: at, -: 97: dollar, -: 98: dotDot, -: 99: ellipsis, -:100: optAccess, -:101: // assign -:102: ass, -:103: mulAss, -:104: divAss, -:105: modAss, -:106: plusAss, -:107: minusAss, -:108: ampAss, -:109: pipeAss, -:110: xorAss, -:111: lshiftAss, -:112: rshiftAss, -:113: tidAss, -:114: optAss, -:115: // arithmetic, bitwise operators -:116: mul, -:117: div, -:118: mod, -:119: plus, -:120: minus, -:121: amp, -:122: pipe, -:123: tidle, -:124: lShift, -:125: rShift, -:126: xor, -:127: // relational operators -:128: equal, -:129: notEqual, -:130: greater, -:131: greaterEqual, -:132: lesser, -:133: lesserEqual, -:134: // logical operators -:135: andAnd, -:136: orOr, -:137: // postfixes -:138: minMin, -:139: plusPlus, -:140:} -:141: -:142:/// Set of TokenType, mostly used by the parser -:143://alias TokenTypes = bool[TokenType]; -:144: -:145:enum ExtendedTokenType: TokenType -:146:{ -:147: // additional ExpressionAstNode.operator -:148: eopArray = 115, -:149: eopIndex, -:150: eopSlice, -:151: eopPreTidle, -:152: eopNeg, -:153: eopDeref, -:154: eopAt, -:155: eopPreInc, -:156: eopPreDec, -:157: eopType, -:158: eopLength, -:159: eopPtr, -:160: eopSetLength, -:161: eopOpOvMacro, -:162: eopDecl, -:163: eopLambda, -:164: eopRefCount, -:165: eopRcaAssign, -:166: // additional StatementAstNode.kind -:167: skContinueOn = 133, -:168: skBreakOn, -:169: // additional DeclarationAstNode.kind -:170: dkEnumMembr = 135, -:171: generic, -:172: // additional TypeAstNode.kind -:173: tkSlice = 137, -:174: tkSta, -:175: tkUnamb, -:176: tkVoid, -:177: tkEnumSet, -:178: tkRca, -:179:} -:180: -:181:/// Returns: the string representation of a `TokenType` -:182:const s8[][ExtendedTokenType.max + 1] tokenString = -:183:[ -:184: "(invalid)", -:185: "(eof)", -:186: "(id)", -:187: // -:188: "(intLiteral)", -:189: "(floatLiteral)", -:190: "(hexLiteral)", -:191: "(binLiteral)", -:192: "(stringLiteral)", -:193: "(rawStringLiteral)", -:194: // -:195: "(//)", -:196: "(/* */)", -:197: // Keywords -:198: "alias", -:199: "apply", -:200: "assert", -:201: "asm", -:202: "auto", -:203: "break", -:204: "class", -:205: "const", -:206: "continue", -:207: "delete", -:208: "do", -:209: "echo", -:210: "else", -:211: "enum", -:212: "false", -:213: "foreach", -:214: "function", -:215: "goto", -:216: "if", -:217: "import", -:218: "in", -:219: "label", -:220: "new", -:221: "null", -:222: "on", -:223: "overload", -:224: "protection", -:225: "return", -:226: "static", -:227: "struct", -:228: "super", -:229: "switch", -:230: "this", -:231: "true", -:232: "union", -:233: "unit", -:234: "var", -:235: "version", -:236: "with", -:237: "while", -:238: // basic types -:239: "bool", -:240: "f32", -:241: "f64", -:242: "s16", -:243: "s32", -:244: "s64", -:245: "s8", -:246: "ssize", -:247: "u16", -:248: "u32", -:249: "u64", -:250: "u8", -:251: "usize", -:252: // symbols -:253: "!", -:254: "?", -:255: ":", -:256: ",", -:257: ".", -:258: ";", -:259: "{", -:260: "(", -:261: "[", -:262: "}", -:263: ")", -:264: "]", -:265: "@", -:266: "$", -:267: "..", -:268: "...", -:269: "?.", -:270: // assign -:271: "=", -:272: "*=", -:273: "/=", -:274: "%=", -:275: "+=", -:276: "-=", -:277: "&=", -:278: "|=", -:279: "^=", -:280: "<<=", -:281: ">>=", -:282: "~=", -:283: "?=", -:284: // arithmetic, bitwise operators -:285: "*", -:286: "/", -:287: "%", -:288: "+", -:289: "-", -:290: "&", -:291: "|", -:292: "~", -:293: "<<", -:294: ">>", -:295: "^", -:296: // relational operators -:297: "==", -:298: "!=", -:299: ">", -:300: ">=", -:301: "<", -:302: "<=", -:303: // logical operators -:304: "&&", -:305: "||", -:306: // postfixes -:307: "--", -:308: "++", -:309: // additional ExpressionAstNode.operator -:310: "(eopArray)", -:311: "(eopIndex)", -:312: "(eopSlice)", -:313: "~", -:314: "-", -:315: "*", -:316: "&", -:317: "++", -:318: "--", -:319: "(eopType)", -:320: "(.length)", -:321: "(.ptr)", -:322: "(.length = )", -:323: "(eopOpOvMacro)", -:324: "(eopDecl)", -:325: "function() => exp;", -:326: "(eopRefCount)", -:327: "(eopRcaAssign)", -:328: // additional StatementAstNode.kind -:329: "(continue on)", -:330: "(break on)", -:331: // additional DeclarationAstNode.kind -:332: "(dkEnumMember)", -:333: "(generic)", -:334: // additional TypeAstNode.kind -:335: "(tkSlice)", -:336: "(tkSta)", -:337: "(tkUnamb)", -:338: "void", -:339: "(tkEnumSet)", -:340: "(tkRca)" -:341:]; -:342: -:343:/// Returns: if the token is for a relational operator -:344:function isRelational(ExtendedTokenType tt): bool -:345:{ 72505:346: return ExtendedTokenType.equal <= tt && tt <= ExtendedTokenType.lesserEqual; -:347:} -:348: -:349:/// Internable string type -:350:struct String -:351:{ -:352: /// -:353: var s8[+] str; -:354: /// -:355: @constructor function create(s8[] text) -:356: { 56268:357: str = text; 56268:358: } -:359: /// -:360: @destructor function destroy() -:361: { 56268:362: str.decref; 56268:363: } -:364: /// -:365: function array(): s8[+] -:366: { 3:367: return str; -:368: } -:369:} -:370: -:371:/** Storage for the unique address of interned String. -:372: -:373: The goal here is not to save memory but uniquely to reduce the time complexity -:374: of the Symbol.searchXXXX functions */ -:375:struct StringAddrPool -:376:{ -:377:protection (private) -:378: -:379: var static String*[+][16384] entries; -:380: -:381: static function hash(s8* data; const usize length): u16 -:382: { -:383: version X86_64 do -:384: { 132868:385: var usize h = 0xCBF29CE484222325; 132868:386: foreach const auto i in 0 .. length do -:387: { 827248:388: h ^= *data++; 827248:389: h *= 0x100000001B3; -:390: } -:391: } -:392: else do version X86 do -:393: { -:394: var usize h = 0x811C9DC5; -:395: foreach const auto i in 0 .. length do -:396: { -:397: h ^= *data++; -:398: h *= 0x1000193; -:399: } -:400: } 132868:401: return (h % 16384): u16; -:402: } -:403: -:404:protection (public) -:405: -:406: @destructor static function destroy() -:407: { 374:408: foreach const usize i in 0 .. entries.length do -:409: { 6127616:410: foreach const String* s in entries.ptr[i] do 38709:411: delete s; 6127616:412: entries.ptr[i].decref; -:413: } 374:414: } -:415: -:416: /// Returns: a pointer to a string, interned -:417: static function intern(s8[] text): String* -:418: { 132868:419: const u16 h = hash(text.ptr, text.length) % 16384; 132868:420: foreach const String* i in entries.ptr[h] do 100198:421: if i.str[] == text do 94159:422: return i; 38709:423: const auto i = entries.ptr[h].length++; 38709:424: return entries.ptr[h].ptr[i] = (new String).create(text); -:425: } -:426: -:427: /// Returns: a pointer to a string, not interned -:428: static function nonintern(s8[] text): String* -:429: { 17559:430: return (new String).create(text); -:431: } -:432:} -:433:/// -:434:@unittest function test2() -:435:{ -:436: const String* s1 = StringAddrPool.intern("hello"); -:437: const String* s2 = StringAddrPool.intern("hello"); -:438: -:439: assert(s1.array() == s2.array()); -:440: assert(s1 == s2); -:441:} -:442: -:443:@unittest function testBucketLeak() -:444:{ -:445: // with FNV, both idents have the same hash, which reveals a case of #289 -:446: const String* s1 = StringAddrPool.intern("styx"); -:447: const String* s2 = StringAddrPool.intern("parseReturnStatement"); -:448: const String* s3 = StringAddrPool.intern("parseReturnStatement"); -:449:} -:450: -:451:function getIdentifierKind(const s8[] str): TokenType -:452:{ 204776:453: var TokenType result = TokenType.id; 614328:454: switch str do -:455: { 407:456: on "alias" do result = $alias; 127:457: on "apply" do result = $apply; 52:458: on "asm" do result = $asm; 2387:459: on "assert" do result = $assert; 3080:460: on "auto" do result = $auto; 801:461: on "bool" do result = $bool; 734:462: on "break" do result = $break; 508:463: on "class" do result = $class; 4097:464: on "const" do result = $const; 305:465: on "continue" do result = $continue; 231:466: on "delete" do result = $delete; 9985:467: on "do" do result = $do; 1104:468: on "echo" do result = $echo; 1745:469: on "else" do result = $else; 461:470: on "enum" do result = $enum; 33:471: on "f32" do result = $f32; 84:472: on "f64" do result = $f64; 633:473: on "false" do result = $false; 661:474: on "foreach" do result = $foreach; 6219:475: on "function" do result = $function; 17:476: on "goto" do result = $goto; 5430:477: on "if" do result = $if; 158:478: on "import" do result = $import; 865:479: on "in" do result = $in; 22:480: on "label" do result = $label; 975:481: on "new" do result = $new; 1087:482: on "null" do result = $null; 1758:483: on "on" do result = $on; 73:484: on "overload" do result = $overload; 179:485: on "protection" do result = $protection; 4303:486: on "return" do result = $return; 80:487: on "s16" do result = $s16; 2510:488: on "s32" do result = $s32; 174:489: on "s64" do result = $s64; 2349:490: on "s8" do result = $s8; 210:491: on "ssize" do result = $ssize; 889:492: on "static" do result = $static; 462:493: on "struct" do result = $struct; 119:494: on "super" do result = $super; 348:495: on "switch" do result = $switch; 1048:496: on "this" do result = $this; 1182:497: on "true" do result = $true; 307:498: on "u16" do result = $u16; 1156:499: on "u32" do result = $u32; 607:500: on "u64" do result = $u64; 2385:501: on "u8" do result = $u8; 38:502: on "union" do result = $union; 1219:503: on "unit" do result = $unit; 1733:504: on "usize" do result = $usize; 6889:505: on "var" do result = $var; 178:506: on "version" do result = $version; 518:507: on "while" do result = $while; 39:508: on "with" do result = $with; 131815:509: else do {} -:510: } 204776:511: return result; -:512:} -:513: -:514:struct Token -:515:{ -:516: -:517:protection (private) -:518: -:519: var String* ttext; -:520: var bool isDollarKw; -:521: -:522: /* The source is maintained as a storage for the token text so escapes -:523: in string literals need to be processed from the constant storage*/ -:524: function postProcessStringLiteral(const s8[] rawText): s8[+] -:525: { 3726:526: var s8[+] result = (new s8[+])(rawText.length); -:527: var usize i; -:528: var usize j; -:529: 3726:530: while i < rawText.length do -:531: { 80014:532: if rawText.ptr[i] == "\\" do -:533: { 445:534: switch rawText.ptr[++i] do -:535: { -:536: on "0" do -:537: { 67:538: result.ptr[j] = "\0"; 134:539: ++i; ++j; 67:540: continue; -:541: } -:542: on "a" do -:543: { 1:544: result.ptr[j] = "\a"; 2:545: ++i; ++j; 1:546: continue; -:547: } -:548: on "b" do -:549: { 1:550: result.ptr[j] = "\b"; 2:551: ++i; ++j; 1:552: continue; -:553: } -:554: on "f" do -:555: { 3:556: result.ptr[j] = "\f"; 6:557: ++i; ++j; 3:558: continue; -:559: } -:560: on "n" do -:561: { 232:562: result.ptr[j] = "\n"; 464:563: ++i; ++j; 232:564: continue; -:565: } -:566: on "r" do -:567: { 13:568: result.ptr[j] = "\r"; 26:569: ++i; ++j; 13:570: continue; -:571: } -:572: on "t" do -:573: { 51:574: result.ptr[j] = "\t"; 102:575: ++i; ++j; 51:576: continue; -:577: } -:578: on "v" do -:579: { 3:580: result.ptr[j] = "\v"; 6:581: ++i; ++j; 3:582: continue; -:583: } -:584: on "\"" do -:585: { 24:586: result.ptr[j] = "\""; 48:587: ++i; ++j; 24:588: continue; -:589: } -:590: on "\\" do -:591: { 14:592: result.ptr[j] = "\\"; 28:593: ++i; ++j; 14:594: continue; -:595: } -:596: on "x" do -:597: { 36:598: var u8 hi = rawText.ptr[i+1]; 36:599: var u8 lo = rawText.ptr[i+2]; 36:600: hi = hi <= "9" ? hi - "0" else hi <= "F" ? 10:u8 + hi - "A" else 10:u8 + hi - "a"; 36:601: lo = lo <= "9" ? lo - "0" else lo <= "F" ? 10:u8 + lo - "A" else 10:u8 + lo - "a"; 36:602: result.ptr[j] = (hi << 4) + lo; 72:603: i += 3; ++j; 36:604: continue; -:605: } -:606: // invalid escape already rejected by the lexer -:607: else do { assert(0); } -:608: } -:609: } 79569:610: result.ptr[j] = rawText.ptr[i]; 159138:611: ++i; ++j; 79569:612: continue; -:613: } 3726:614: return result.ptr[0..j]; -:615: } -:616: -:617:protection (public) -:618: -:619: var ExtendedTokenType type; -:620: var Position position; -:621: var Token* prev; -:622: -:623: /** -:624: * Constructs a new token. -:625: * -:626: * Params: -:627: * start = Pointer to the first character. Must live longer than the token. -:628: * stop = Pointer to the last character. Must live longer than the token. -:629: * line = The line, 1 based, where the token starts. -:630: * column = The column, 1 based, where the token starts. -:631: * type = The token type. The keywords are only detected from here. -:632: */ -:633: @constructor function create(s8[] text; u32 line; u32 column; ExtendedTokenType type) -:634: { 423876:635: this.position = (line, column); 423876:636: this.type = type == TokenType.id ? getIdentifierKind(text) else type; -:637: 423876:638: const auto tlen = text.length; 423876:639: if tlen > 1 && type == TokenType.id && text.ptr[0] == "$" do -:640: { 1101:641: text = text.ptr[1 .. tlen]; 1101:642: --column; 1101:643: isDollarKw = true; -:644: } -:645: -:646: // `postProcessStringLiteral()` result lifetime LT `text`'s one -:647: var s8[+] ppstring; 423876:648: if this.type == TokenType.stringLiteral do -:649: { 3726:650: ppstring = postProcessStringLiteral(text); 3726:651: text = ppstring; -:652: } -:653: 423876:654: switch this.type do -:655: { -:656: on TokenType.id, TokenType.$this do 132863:657: ttext = StringAddrPool.intern(text); -:658: on invalid, intLiteral .. starComment do 17559:659: ttext = StringAddrPool.nonintern(text); 273454:660: else do {} -:661: } 423876:662: } -:663: -:664: @destructor function destroy() -:665: { 402328:666: if type != TokenType.id && this.type != TokenType.$this && ttext do 17559:667: delete ttext; 402328:668: } -:669: -:670: static function generateIdentifier(): Token* -:671: { -:672: static var u32 cnt; 3519:673: return identifier("__tmp" ~ cnt++.toString()); -:674: } -:675: -:676: static function generateIdentifierFromPos(Position p; s8[] prefix): Token* -:677: { -:678: static var u32 cnt; 31:679: return identifier(prefix ~ "L" ~ p.line.toString() ~ "C" ~ p.column.toString()); -:680: } -:681: -:682: /// Returns: $(D true) if the identifier is a keyword prefixed with dollar. 5103:683: function keywordAsIdentifier(): bool {return isDollarKw;} -:684: -:685: /// Returns: The line, 1 based, where the token starts. 3:686: function line(): u32 {return position.line;} -:687: -:688: /// Returns: The column, 1 based, where the token starts. 1:689: function column(): u32 {return position.column;} -:690: -:691: /// Returns: The pointer used for fast comparisons of identifiers 10406477:692: @inline(true) function iptr(): u8* { return ttext:u8*; } -:693: -:694: /// Returns: The token text. -:695: function text(): s8[+] -:696: { 163783:697: return ttext ? ttext.str else tokenString[type]; -:698: } -:699: -:700: /// Conveniance function used by the parser. -:701: function isTokBasicType(): bool -:702: { 19747:703: return TokenType.$bool <= type && type <= TokenType.$usize; -:704: } -:705: -:706: /// Conveniance function used by the parser. 1622:707: function isTokKeyword(): bool {return TokenType.$alias <= type && type <= TokenType.$while;} -:708: -:709: /// Conveniance function used by the parser. 56825:710: function isTokStorageClass(): bool {return type == $var || type == $const || type == $static;} -:711: -:712: /// Conveniance function used by the parser. 771286:713: function isTok[ExtendedTokenType ett](): bool { return type == ett; } -:714:} -:715: -:716:function stringRepresentation(const Token* t): s8[+] -:717:{ 152:718: if t.type != TokenType.stringLiteral do 1:719: return t.ttext.array(); -:720: -:721: // *4 : in case all chars must be output using hex escapes 151:722: var s8[+] result = (new s8[+])(t.ttext.str.length * 4 + 1); -:723: var usize i; -:724: var usize j; 151:725: while i != t.ttext.str.length do -:726: { 842:727: const s8 c = t.ttext.str.ptr[i]; 842:728: switch c do -:729: { -:730: on "\\" do -:731: { 1:732: result.ptr[j .. j + 2] = `\\`; 1:733: j += 2; -:734: } -:735: on "\"" do -:736: { 4:737: result.ptr[j .. j + 2] = `\"`; 4:738: j += 2; -:739: } -:740: on 0 .. 31 do -:741: { 11:742: result.ptr[j++] = `\`; 11:743: result.ptr[j++] = `x`; 11:744: var u8 hi = (c >> 4) & 0xF; 11:745: result.ptr[j++] = hi < 10 ? hi + "0" else (hi - 10) + "A"; 11:746: var u8 lo = (c ) & 0xF; 11:747: result.ptr[j++] = lo < 10 ? lo + "0" else (lo - 10) + "A"; -:748: } -:749: else do -:750: { 826:751: result.ptr[j] = c; 826:752: ++j; -:753: } -:754: } 842:755: ++i; -:756: } 151:757: result[j++] = 0; 151:758: return result[0 .. j-1]; -:759:} -:760: -:761:/// Returns: a Token of type identifier for the input string. -:762:function identifier(s8[] text): Token* -:763:{ 25047:764: return (new Token).create(text, 0, 0, ExtendedTokenType.id); -:765:} -:766: -:767:/// -:768:struct StaticTok[S] -:769:{ -:770: static var Token* tok; -:771: @destructor static function destroy() -:772: { 13857:773: if tok do delete tok; 11220:774: } -:775: @operator(call()) static function get(): Token* -:776: { 113427:777: return tok ?= identifier(S); -:778: } -:779:} -:780: -:781:/// Returns: The Token used to identify the `intel` identifier. -:782:alias asmFlavIntelToken = apply(StaticTok, "intel"); -:783: -:784:/// Returns: The Token used to identify the `att` identifier. -:785:alias asmFlavAttToken = apply(StaticTok, "att"); -:786: -:787:/// Returns: The Token used to identify the `deprecated` identifier. -:788:alias deprecatedToken = apply(StaticTok, "deprecated"); -:789: -:790:/// Returns: The Token used to identify the `func_t` echo. -:791:alias echoFunctToken = apply(StaticTok, "func_t"); -:792: -:793:/// Returns: The Token used to identify the `type` echo. -:794:alias echoTypeToken = apply(StaticTok, "type"); -:795: -:796:/// Returns: The Token used to identify the `foreign` identifier. -:797:alias foreignToken = apply(StaticTok, "foreign"); -:798: -:799:/// Returns: The Token used to identify the `getPointedType` identifier. -:800:alias echoGetPointedTypeToken = apply(StaticTok, "getPointedType"); -:801: -:802:/// Returns: The Token used to identify the `inline` identifier. -:803:alias inlineToken = apply(StaticTok, "inline"); -:804: -:805:/// Returns: The Token used to identify the libc `fflush`. -:806:alias libcFFlushToken = apply(StaticTok, "fflush"); -:807: -:808:/// Returns: The Token used to identify the libc `printf`. -:809:alias libcPrintfToken = apply(StaticTok, "printf"); -:810: -:811:/// Returns: The Token used to identify the libc `realloc`. -:812:alias libcReallocToken = apply(StaticTok, "realloc"); -:813: -:814:/// Returns: The Token used to identify libc `memcmp`. -:815:alias libcMemcmpToken = apply(StaticTok, "memcmp"); -:816: -:817:/// Returns: The Token used to identify the `LLVM` identifier. -:818:alias llvmToken = apply(StaticTok, "LLVM"); -:819: -:820:/// Returns: The Token used to identify the `main` identifier. -:821:alias mainToken = apply(StaticTok, "main"); -:822: -:823:/// Returns: The Token used to identify the `operator` identifier. -:824:alias operatorToken = apply(StaticTok, "operator"); -:825: -:826:/// Returns: The Token used to identify the `private` identifier. -:827:alias privateToken = apply(StaticTok, "private"); -:828: -:829:/// Returns: The Token used to identify the `length` property. -:830:alias propLengthToken = apply(StaticTok, "length"); -:831: -:832:/// Returns: The Token used to identify the `expand` property. -:833:alias propExpandToken = apply(StaticTok, "expand"); -:834: -:835:/// Returns: The Token used to identify the `protected` identifier. -:836:alias protectedToken = apply(StaticTok, "protected"); -:837: -:838:/// Returns: The Token used to identify the `public` identifier. -:839:alias publicToken = apply(StaticTok, "public"); -:840: -:841:/// Returns: The Token used to `reverse` property. -:842:alias reverseToken = apply(StaticTok, "reverse"); -:843: -:844:/// Returns: The Token used to identify the the rtl import name. -:845:alias rtlToken = apply(StaticTok, "rtl"); -:846: -:847:/// Returns: The Token used to identify the `strict` identifier. -:848:alias strictToken = apply(StaticTok, "strict"); -:849: -:850:/// Returns: The Token used to identify the hidden `this` parameter. -:851:alias thisToken = apply(StaticTok, "this"); -:852: -:853:/// Returns: The Token used to identify the `unittest` identifier. -:854:alias unittestToken = apply(StaticTok, "unittest"); -:855: -:856:/// Returns: The Token used to replace the compiler echo giving the semver string. -:857:alias versionToken = apply(StaticTok, "0.10.4"); -:858: -:859:/// Returns: The Token used to name the virtual table. -:860:alias vtableToken = apply(StaticTok, "#vtable"); -:861: -:862:/// Returns: The Token used to identify the `__sx_obj_equal` Object function. -:863:alias objEqualToken = apply(StaticTok, "__sx_obj_equal"); -:864: -:865:/// Returns: The Token used to identify the `Object` class name. -:866:alias objectToken = apply(StaticTok, "Object"); -:867: -:868:/// Returns: The Token used to identify the `RcArray` type name. -:869:alias rcArrayToken = apply(StaticTok, "RcArray"); -:870: -:871:/** -:872: * Formats an array of Token pointers as text. -:873: * -:874: * Params: -:875: * toks = The array to format. -:876: */ -:877:function tokenChainText(const Token*[] toks): s8[+] -:878:{ 7845:879: var Token* t0 = toks[0]; 7845:880: if toks.length == 1 do 908:881: return t0.text(); -:882: -:883: var s8[+] result; 6937:884: foreach (const auto i; const Token* t) in toks do -:885: { 22436:886: result ~= t.text(); 22436:887: if i != toks.length - 1 do 15499:888: result ~= "."; -:889: } 6937:890: return result; -:891:} -:892:/// -:893:@unittest function test4() -:894:{ -:895: var Token* t0 = (new Token).create("one", 0, 0, TokenType.id); -:896: var Token* t1 = (new Token).create("two", 0, 0, TokenType.id); -:897: var Token*[+] toks = [t0, t1]; -:898: -:899: assert(toks.tokenChainText() == "one.two"); -:900: -:901: assert([t0].tokenChainText() == "one"); -:902: delete t0; -:903: delete t1; -:904:} -:905: -:906:@unittest function test5() -:907:{ -:908: var Token* t0 = (new Token).create("unit", 0, 0, TokenType.id); -:909: assert(t0.isTok:[$unit]()); -:910: delete t0; -:911:} -:912: -:913:@unittest function test6() -:914:{ -:915: var Token* t0 = (new Token).create("$function", 0, 0, TokenType.id); -:916: assert(t0.isTok:[id]()); -:917: assert(t0.stringRepresentation() == "function"); -:918: delete t0; -:919:} <<<<<< EOF # path=tests/backend/andand_oror.gcov -: 0:Source:/builds/styx-lang/styx/tests/backend/andand_oror.sx -: 1:unit andand_oror; -: 2: -: 3:var s32 evaluated; 10: 4:function f1(): bool { evaluated +=1; return false; } 6: 5:function f2(): bool { evaluated +=1; return false; } 20: 6:function t1(): bool { evaluated +=1; return true; } -: 7: -: 8:function test1() -: 9:{ -: 10: var bool result; 1: 11: evaluated = 0; 1: 12: if f1() && 0: 13: f2() do {result = true;} 1: 14: assert(evaluated == 1); 1: 15: assert(result == false); 1: 16: return; -: 17:} -: 18: -: 19:function test2() -: 20:{ -: 21: var bool result; 1: 22: evaluated = 0; 1: 23: if t1() && f2() do {result = true;} 1: 24: assert(evaluated == 2); 1: 25: assert(result == false); 1: 26: return; -: 27:} -: 28: -: 29:function test3() -: 30:{ -: 31: var bool result; 1: 32: evaluated = 0; 2: 33: if t1() && t1() do {result = true;} 1: 34: assert(evaluated == 2); 1: 35: assert(result == true); 1: 36: return; -: 37:} -: 38: -: 39:function test4() -: 40:{ -: 41: var bool result; 1: 42: evaluated = 0; 1: 43: if f1() || f2() do {result = true;} 1: 44: assert(evaluated == 2); 1: 45: assert(result == false); 1: 46: return; -: 47:} -: 48: -: 49:function test5() -: 50:{ -: 51: var bool result; 1: 52: evaluated = 0; 1: 53: if t1() || 1: 54: f2() do {result = true;} 1: 55: assert(evaluated == 1); 1: 56: assert(result); 1: 57: return; -: 58:} -: 59: -: 60:function testCombined1() -: 61:{ -: 62: var bool result; 1: 63: evaluated = 0; 2: 64: if t1() && t1() && t1() do {result = true;} 1: 65: assert(evaluated == 3); 1: 66: assert(result); 1: 67: return; -: 68:} -: 69: -: 70:function testCombined2() -: 71:{ -: 72: var bool result; 1: 73: evaluated = 0; 2: 74: if f1() || f2() || t1() do {result = true;} 1: 75: assert(evaluated == 3); 1: 76: assert(result); 1: 77: return; -: 78:} -: 79: -: 80:function testCombined3() -: 81:{ -: 82: var bool result; 1: 83: evaluated = 0; 1: 84: if f1() && (f2() || t1()) do {result = true;} 1: 85: assert(evaluated == 1); 1: 86: assert(!result); 1: 87: return; -: 88:} -: 89: -: 90:function testCombined4() -: 91:{ -: 92: var bool result; 1: 93: evaluated = 0; 2: 94: if (f1() || (t1()) && t1()) do {result = true;} 1: 95: assert(evaluated == 3); 1: 96: assert(result); 1: 97: return; -: 98:} -: 99: -:100:function main(): s32 -:101:{ -:102: 1:103: test1(); 1:104: test2(); 1:105: test3(); 1:106: test4(); 1:107: test5(); -:108: 1:109: testCombined1(); 1:110: testCombined2(); 1:111: testCombined3(); 1:112: testCombined4(); -:113: 1:114: return 0; -:115:} <<<<<< EOF # path=tests/backend/cond_exp.gcov -: 0:Source:/builds/styx-lang/styx/tests/backend/cond_exp.sx -: 1:unit cond_exp; -: 2: -: 3:function getTrue(): bool -: 4:{ 1: 5: return true; -: 6:} -: 7: -: 8:function getFalse(): bool -: 9:{ 1:10: return false; -:11:} -:12: -:13:var s32 eo; -:14:function evalOnce(): s32 -:15:{ 1:16: eo+=1; 1:17: return eo; -:18:} -:19: -:20:function main(): s32 -:21:{ 1:22: var s32 trueValue = 2; 1:23: var s32 falseValue = 8; -:24: 1:25: const auto a = getTrue() ? trueValue 0:26: else falseValue; 1:27: assert(a == 2); 1:28: const auto b = getFalse() ? trueValue 1:29: else falseValue; 1:30: assert(b == 8); 1:31: const auto c = a == 1 ? 0 else a == 45 ? 1 else 3; 1:32: assert(c == 3); -:33: 1:34: assert(true && true && true || false); -:35: 1:36: const auto d = 1 ? 0; 1:37: assert(d == 1); 1:38: const auto e = 0 ? 1; 1:39: assert(e == 1); -:40: 1:41: const auto f = evalOnce() ? 8:u64; 1:42: assert(f == 1); 1:43: assert(eo == 1); 1:44: assert((1 ? 0) == 1); 1:45: assert((0 ? 1) == 1); // 0 != 0 ... 1:46: assert((0 != 1 ? 1) == 0); -:47: 1:48: test_AssAndVoid(); 1:49: test450(); 1:50: test474(); 1:51: return 0; -:52:} -:53: -:54:function test_AssAndVoid() -:55:{ 1:56: static function f(){} -:57: var s32 a; 1:58: a ? f() else (a = 1); 1:59: return a ? f() else (a = 1); -:60:} -:61: -:62:function test450() -:63:{ -:64: struct S -:65: { -:66: static var s32 a; -:67: static var s32 b; -:68: } -:69: -:70: 1:71: (true ? S.a else S.b) = 1; 1:72: assert(S.a == 1); -:73: 1:74: (S.a ? S.b) = 2; 1:75: assert(S.a == 2); 1:76:} -:77: -:78:function test474() -:79:{ -:80: var u32[] a; -:81: 1:82: var u32[] b0 = a ? a else [0][]; // OK 1:83: var u32[] b1 = a ? [0][]; // NG 1:84: assert(b1 == [0]); 1:85:} <<<<<< EOF # path=tests/backend/cover_empty_switch_matches.gcov -: 0:Source:/builds/styx-lang/styx/tests/backend/cover_empty_switch_matches.sx -: 1:unit cover_empty_switch_matches; -: 2: -: 3:function main(): s32 -: 4:{ 1: 5: foreach const auto i in 0 .. 3 do 3: 6: switch i do -: 7: { 1: 8: on 0 do {} 1: 9: on 1 do {} 1:10: else do {} -:11: } 1:12: return 0; -:13:} <<<<<< EOF # path=tests/backend/rca_elem_dtor.gcov -: 0:Source:/builds/styx-lang/styx/tests/backend/rca_elem_dtor.sx -: 1:unit rca_elem_dtor; -: 2: -: 3:var s32 count; -: 4: -: 5:struct S -: 6:{ -: 7: var s8 a = 8; -: 8: -: 9: @constructor function create() -:10: { 5:11: count++; 5:12: } -:13: -:14: @destructor function destroy() -:15: { 5:16: count--; 5:17: } -:18:} -:19: -:20:@destructor function unitFinalizer() -:21:{ 1:22: assert(count == 0); 1:23:} -:24: -:25:static var u8* previous; -:26: -:27:struct S2 -:28:{ -:29: var s8[19] _; -:30: @destructor function destroy() -:31: { 3:32: const auto p = this:u8*; 3:33: assert(previous >= (previous ?= p)); 3:34: previous = p; 3:35: printf("previous=%p\n", p); 3:36: } -:37:} -:38: -:39:function main(): s32 -:40:{ -:41: var S[+] s; 1:42: s.length += 2; 1:43: assert(count == 2); 1:44: s.length -= 2; 1:45: assert(count == 0); 1:46: s.length += 3; 1:47: assert(count == 3); -:48: -:49: var S2[+] s2; 1:50: s2.length = 3; 1:51: s2.length = 0; -:52: 1:53: return 0; -:54:} <<<<<< EOF # path=src/styx/ast/base.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/ast/base.sx -: 1:/** -: 2:The base nodes of the AST -: 3: -: 4:The AST consists of 4 types of nodes -: 5: -: 6:- Declaration -: 7:- Statement -: 8:- Expression -: 9:- Type -: 10: -: 11:The whole AST can be described using those base nodes. -: 12:*/ -: 13:unit styx.ast.base; -: 14: -: 15:@private import -: 16: styx.position, -: 17: styx.symbol, -: 18: styx.scope, -: 19: styx.token, -: 20: styx.ast.visitor, -: 21: ; -: 22: -: 23:/// Used in declaration semantic, mostly to detect circular references. -: 24:enum SemanticProgress : u8 -: 25:{ -: 26: pending, /// not checked -: 27: running, /// being checked -: 28: done, /// already done -: 29: irgened, /// IR generated -: 30:} -: 31: -: 32:/// Enumerates the possible level of protection a declaration can have. -: 33:enum Protection : u8 -: 34:{ -: 35: public, /// always visible -: 36: protected, /// visible in foregin module if derived from the declaration -: 37: private, /// not visible in foreign module -: 38: strict, /// not visible even in current module -: 39:} -: 40: -: 41:/// The base AST node. -: 42:class AstNode -: 43:{ -: 44: /// Position in source -: 45: var Position startPos; -: 46: /// Placeholder for the intermediate representation -: 47: @@Semantic var u8* ir; -: 48: /// Get visited by an AstVisitor. 24532: 49: @virtual function accept(AstVisitor* visitor) {} -: 50: /// To free the fields that are RC arrays, classes pointers and not annotated `@@Semantic` -: 51: @virtual function free() -: 52: { -: 53: //printf("AstNode.free() this=%p\n", this); 22471: 54: delete this; 22471: 55: } -: 56: /// Free is used instead, to have a better control on special instances such as singleton -: 57: @destructor function destroy() -: 58: { -: 59: //printf("AstNode.destroy() this=%p\n", this); -: 60: //filename.decref; 22471: 61: } -: 62: /// 81436: 63: @virtual function asDeclaration(): Declaration* {return null;} -: 64: /// 0: 65: @virtual function asType(): Type* {return null;} -: 66:} -: 67: -: 68:/// Attribute -: 69:@final class Attribute : AstNode -: 70:{ -: 71: /// the identifier -: 72: var Token* identifier; -: 73: /// the arguments -: 74: var Expression*[+] arguments; -: 75: /// -: 76: var bool isUser; -: 77: /// -: 78: @constructor function create(var Position startPos; const Token* identifier; bool isUser) -: 79: { 1653: 80: this.startPos = startPos; 1653: 81: this.identifier = identifier; 1653: 82: this.isUser = isUser; 1653: 83: } -: 84: /// -: 85: @override function accept(AstVisitor* visitor) -: 86: { 1488: 87: foreach var auto arg in arguments do 296: 88: visitor.visitExpression(arg); 1488: 89: } -: 90: /// -: 91: @override function free() -: 92: { 126: 93: foreach var auto a in arguments do 50: 94: a.free(); 126: 95: arguments.decref; 126: 96: super(); 126: 97: } -: 98:} -: 99: -:100:const s8[][NoArgAttribute.max + 1] noArgAttributeStrings = [ -:101: "@abstract", -:102: "@constructor", -:103: "@destructor", -:104: "@final", -:105: "@noinit", -:106: "@noopt", -:107: "@noreturn", -:108: "@override", -:109: "@return", -:110: "@tls", -:111: "@virtual", -:112:]; -:113: -:114:/// Attributes that dont require a matching AST node -:115:enum NoArgAttribute : u16 -:116:{ -:117: atAbstract, -:118: atConstructor, -:119: atDestructor, -:120: atFinal, -:121: atNoinit, -:122: atNoopt, -:123: atNoReturn, -:124: atOverride, -:125: atReturn, -:126: atTLS, -:127: atVirtual, -:128:} -:129: -:130:alias NoArgAttributes = bool[NoArgAttribute]; -:131: -:132:/// Attributes -:133:@final class Attributes : AstNode -:134:{ -:135: /// @asm -:136: var Attribute* atAsm; -:137: /// @deprecated -:138: var Attribute* atDeprecated; -:139: /// @foreign -:140: var Attribute* atForeign; -:141: /// @inline -:142: var Attribute* atInline; -:143: /// @LLVM -:144: var Attribute* atLLVM; -:145: /// @operator -:146: var Attribute* atOperator; -:147: /// @overliad -:148: var Attribute* atOverload; -:149: /// @public, @private, etc. -:150: var Attribute* atProtection; -:151: /// @unittest -:152: var Attribute* atUnittest; -:153: /// user-defined -:154: var Attribute*[+] atUser; -:155: /// -:156: var NoArgAttributes noArgAttributes; -:157: /// -:158: @constructor function create(var Position startPos) -:159: { 3429:160: this.startPos = startPos; 3429:161: } -:162: /// -:163: @override function free() -:164: { 170:165: atAsm?.free(); 170:166: atDeprecated?.free(); 170:167: atForeign?.free(); 170:168: atInline?.free(); 170:169: atLLVM?.free(); 170:170: atOperator?.free(); 170:171: atOverload?.free(); 170:172: atProtection?.free(); 170:173: atUnittest?.free(); 191:174: foreach var auto u in atUser do u.free(); 170:175: atUser.decref; 170:176: super(); 170:177: } -:178: /// -:179: @override function accept(AstVisitor* visitor) -:180: { 7501:181: if atAsm do visitor.visitAttribute(atAsm); 7563:182: if atDeprecated do visitor.visitAttribute(atDeprecated); 8773:183: if atForeign do visitor.visitAttribute(atForeign); 7863:184: if atInline do visitor.visitAttribute(atInline); 7551:185: if atLLVM do visitor.visitAttribute(atLLVM); 7822:186: if atOperator do visitor.visitAttribute(atOperator); 7514:187: if atOverload do visitor.visitAttribute(atOverload); 7752:188: if atProtection do visitor.visitAttribute(atProtection); 7815:189: if atUnittest do visitor.visitAttribute(atUnittest); 7866:190: foreach var auto u in atUser do visitor.visitAttribute(u); 7492:191: } -:192:} -:193: -:194:/// Enumerates the possible storage class a declaration can have. -:195:enum StorageClass : u8 -:196:{ -:197: $const, /// head-const -:198: $static, /// global -:199: $var, /// head-mutable -:200:} -:201: -:202:/// Set of StorageClass -:203:alias StorageClasses = bool[StorageClass]; -:204: -:205:function storageClassesText(const StorageClasses stc): s8[+] -:206:{ -:207: var s8[+] result; 712:208: if $const in stc do result ~= "const "; 746:209: if $static in stc do result ~= "static "; 710:210: if $var in stc do result ~= "var "; 664:211: return result; -:212:} -:213: -:214:/// -:215:enum LinkageKind : u8 -:216:{ -:217: fqn, // CallConv C, name is the fqn -:218: foreign, // CallConv C, name is not qualified -:219:} -:220: -:221:/// Declaration -:222:class Declaration : AstNode -:223:{ -:224: /// Optional scope for func, aggregates, etc. -:225: @@Semantic var Scope* scope; -:226: /// The declaration name -:227: var Token* name; -:228: /// Associated Symbol -:229: @@Semantic var Symbol* symbol; -:230: /// -:231: var Attributes* attributes; -:232: /// The type created for this declaration, e.g a TypeEnum for an EnumDeclaration -:233: @@Semantic var Type* asTypeDeclared; -:234: /// -:235: var GenericParameters* genericParameters; -:236: /// -:237: var Declaration* baseGeneric; -:238: /// All the generic, fully or partial, applications -:239: @@Semantic var Declaration* nextInstance; -:240: /// Cache the symbol name as used during linking -:241: @@Semantic var s8[+] linkageName; -:242: /// A token, used to dispatch to the visitors and to cast faster -:243: var ExtendedTokenType kind; -:244: /// Indicates the declaration protection -:245: var Protection $protection; -:246: /// -:247: var StorageClasses stc; -:248: /// If passed as a CLI -I argument -:249: var bool isHeader; -:250: /// -:251: @@Semantic var SemanticProgress progress; -:252: /// -:253: @@Semantic var LinkageKind linkageKind; -:254: /// -:255: @override function free() -:256: { 2484:257: if scope do delete scope; 2330:258: attributes?.free(); 2330:259: asTypeDeclared?.free(); 2330:260: genericParameters?.free(); 2330:261: super(); 2330:262: } -:263: -:264: /// Returns: if this declaration is generic 198518:265: function isGeneric(): bool { return genericParameters && !genericParameters.applied();} -:266: -:267: /// -:268: @override function accept(AstVisitor* visitor) { assert(0); } -:269: /// 247869:270: @final @override function asDeclaration(): Declaration* {return this;} -:271: -:272: /// Returns: `true` if the declaration is `const`. 54533:273: function isConst(): bool { return $const in stc; } -:274: /// Returns: `true` if the declaration is `static`. 327523:275: function isStatic(): bool { return $static in stc; } -:276: /// Returns: `true` if the declaration is `var`. 160129:277: function isVar(): bool { return $var in stc; } -:278: -:279: /// Returns: If declaration is `@abstract` 23848:280: function getAtAbstract(): bool { return attributes && atAbstract in attributes.noArgAttributes; } -:281: /// Returns: The `@asm` of this declaration 23844:282: function getAtAsm(): Attribute* { return attributes ? attributes.atAsm else null; } -:283: /// Returns: If declaration is `@constructor` 24342:284: function getAtConstructor(): bool { return attributes && atConstructor in attributes.noArgAttributes; } -:285: /// Returns: The `@deprecated` of this declaration 88943:286: function getAtDeprecated(): Attribute* { return attributes ? attributes.atDeprecated else null; } -:287: /// Returns: If declaration is `@destructor 24698:288: function getAtDestructor(): bool { return attributes && atDestructor in attributes.noArgAttributes; } -:289: /// Returns: If declaration is `@final` 32913:290: function getAtFinal(): bool { return attributes && atFinal in attributes.noArgAttributes; } -:291: /// Returns: The `@foreign` of this declaration 83485:292: function getAtForeign(): Attribute* { return attributes ? attributes.atForeign else null; } -:293: /// Returns: The `@inline` of this declaration 23844:294: function getAtInline(): Attribute* { return attributes ? attributes.atInline else null; } -:295: /// Returns: The `@LLVM` of this declaration 23910:296: function getAtLLVM(): Attribute* { return attributes ? attributes.atLLVM else null; } -:297: /// Returns: If declaration is `@noopt` 80763:298: function getAtNoinit(): bool { return attributes && atNoinit in attributes.noArgAttributes; } -:299: /// Returns: If declaration is `@noopt` 42316:300: function getAtNoopt(): bool { return attributes && atNoopt in attributes.noArgAttributes; } -:301: /// Returns: If declaration is `@noreturn` 65035:302: function getAtNoReturn(): bool { return attributes && atNoReturn in attributes.noArgAttributes; } -:303: /// Returns: The `@operator` of this declaration 90601:304: function getAtOperator(): Attribute* { return attributes ? attributes.atOperator else null; } -:305: /// Returns: The `@overload` of this declaration 24127:306: function getAtOverload(): Attribute* { return attributes ? attributes.atOverload else null; } -:307: /// Returns: If declaration is `@override` 24695:308: function getAtOverride(): bool { return attributes && atOverride in attributes.noArgAttributes; } -:309: /// Returns: The `@` of this declaration 13132:310: function getAtProtection(): Attribute* { return attributes ? attributes.atProtection else null; } -:311: /// Returns: If declaration is `@return` 23899:312: function getAtReturn(): bool { return attributes && atReturn in attributes.noArgAttributes; } -:313: /// Returns: If declaration is `@tls` 40324:314: function getAtTLS(): bool { return attributes && atTLS in attributes.noArgAttributes; } -:315: /// Returns: The `@Unittest` of this declaration 109725:316: function getAtUnittest(): Attribute* { return attributes ? attributes.atUnittest else null; } -:317: /// Returns: If declaration is `@virtual` 24913:318: function getAtVirtual(): bool { return attributes && atVirtual in attributes.noArgAttributes; } -:319:} -:320: -:321:/// Describes the effect of a statement on the execution flow -:322:enum FlowKind : u8 -:323:{ -:324: isNext, /// statement does not modify the flow -:325: isGoto, /// statement is (or block terminates with) a GotoStatement -:326: isBreak, /// statement is (or block terminates with) a BreakStatement -:327: isContinue, /// statement is (or block terminates with) a ContinueStatement -:328: isReturn, /// statement is (or block terminates with) a ReturnStatement -:329: isContinueOn, /// -:330: isBreakOn, /// -:331: isNoReturn, /// only for function bodies -:332:} -:333: -:334:alias SetOfFlow = bool[FlowKind]; -:335: -:336:/// Contains the flow information of statements and blocks -:337:struct Flow -:338:{ -:339:protection(private) -:340: -:341: var SetOfFlow cf; -:342: var FlowKind last; -:343: -:344:protection(public) -:345: -:346: @constructor function create(FlowKind cf) -:347: { 55175:348: this.cf += cf; 55175:349: this.last = cf; 55175:350: } -:351: /// 40484:352: function isContinueToNext(): bool { return last == FlowKind.isNext; } -:353: /// 5428:354: function containsContinueToNext(): bool { return FlowKind.isNext in cf; } -:355: /// 734:356: function containsBreak(): bool { return FlowKind.isBreak in cf; } -:357: /// 2293:358: function isNoReturn(): bool { return FlowKind.isNoReturn in cf; } -:359: /// 12961:360: function isReturn(): bool { return last == FlowKind.isReturn; } -:361: /// 3413:362: function isContinue(): bool { return last == FlowKind.isContinue; } -:363: /// 443:364: function isBreak(): bool { return last == FlowKind.isBreak; } -:365: /// 330:366: function isContinueOn(): bool { return last == FlowKind.isContinueOn; } -:367: /// -:368: function hideReturns(): Flow -:369: { 617:370: cf -= FlowKind.isReturn; 617:371: return *this; -:372: } -:373: /// -:374: function onlyReturns(): bool -:375: { 279:376: var Flow* f = this; 279:377: f.hideReturns(); 279:378: return f.cf == 0; -:379: } -:380: /// -:381: function mixBranch(Flow other) -:382: { 6235:383: cf += other.last; 6235:384: last = other.last; 6235:385: } -:386: /// -:387: function pretendLastIsContinueToNext() -:388: { 9844:389: if containsContinueToNext() do last = isNext; 4977:390: } -:391: /// -:392: function mixLinear(Flow other) -:393: { 31907:394: last = other.last; 31907:395: cf += other.cf; 31907:396: } -:397: /// -:398: function includeNext() -:399: { 663:400: cf += isNext; 663:401: } -:402:} -:403: -:404:/// Declarations -:405:@final class Declarations : AstNode -:406:{ -:407: /// The declarations -:408: var Declaration*[+] items; -:409: /// -:410: @constructor function create(var Position startPos; Declaration*[] items = []) -:411: { 2442:412: this.startPos = startPos; 2442:413: this.items = items; 2442:414: } -:415: /// -:416: @override function free() -:417: { 808:418: foreach var auto i in items do 672:419: i.free(); 808:420: items.decref; 808:421: super(); 808:422: } -:423: /// -:424: @override function accept(AstVisitor* visitor) -:425: { 14173:426: foreach var Declaration* d in items do 84068:427: visitor.visitDeclaration(d); 14172:428: } -:429:} -:430: -:431:/// Expression -:432:class Expression : AstNode -:433:{ -:434: /// Associated Symbol -:435: @@Semantic var Symbol* symbol; -:436: /// The expression type -:437: @@Semantic var Type* type; -:438: /// The expression operator -:439: var ExtendedTokenType operator; -:440: /// Count of paren pairs surround the exp -:441: var u8 parens; -:442: /// -:443: @override function free() -:444: { 13224:445: type?.free(); 13224:446: super(); 13224:447: } -:448: /// The base expression is not supposed to be visited -:449: @override function accept(AstVisitor* visitor) { assert(0); } -:450: /// If the expression has an address 91959:451: @virtual function isLvalue(): bool { return false; } -:452: /// If the expression can be an assign LHS 481:453: @virtual function isAssignable(): bool { return isLvalue() && !isLiteral(); } -:454: /// If the expression can be used to initialized a `static` declaration 139:455: @virtual function canInitialize(): bool { return false; } -:456: /// 12842:457: @virtual function isLiteral(): bool { return false; } -:458:} -:459: -:460:/// GenericParameter -:461:class GenericParameter : Declaration -:462:{ -:463: /// -:464: @@Semantic var Expression* appliedExp; -:465: /// -:466: @@Semantic var Type* appliedType; -:467: /// -:468: @@Semantic var Expression* originalExp; -:469: /// -:470: var Type* valueType; -:471: /// -:472: @constructor function create(Position startPos; Token* name; Type* valueType) -:473: { 1064:474: this.kind = generic; 1064:475: this.startPos = startPos; 1064:476: this.name = name; 1064:477: this.valueType = valueType; 1064:478: } -:479: /// -:480: @override function accept(AstVisitor* visitor) -:481: { 793:482: } -:483: /// -:484: function applied(): bool -:485: { 39833:486: return appliedExp != null || appliedType != null; -:487: } -:488: -:489:} -:490: -:491:/// GenericParameters -:492:class GenericParameters : AstNode -:493:{ -:494: /// -:495: var s8[+] linkageName; -:496: /// -:497: var GenericParameter*[+] parameters; -:498: /// -:499: @override function free() -:500: { 9:501: foreach var auto p in parameters do 13:502: p.free(); 9:503: parameters.decref; 9:504: super(); 9:505: } -:506: /// -:507: @override function accept(AstVisitor* visitor) -:508: { 1348:509: foreach var auto p in parameters do 2343:510: visitor.visitGenericParameter(p); 1348:511: } -:512: /// -:513: function applied(): bool -:514: { 33597:515: foreach var auto p in parameters do 38597:516: if !p.applied() do 2148:517: return false; 31449:518: return true; -:519: } -:520:} -:521: -:522:/// Sub Operator for recounting -:523:enum RefCountOp : u8 -:524:{ -:525: dup_, -:526: refcount_, -:527: incref_, -:528: decref_, -:529:} -:530: -:531:/// Statement -:532:class Statement : AstNode -:533:{ -:534: /// If not null the scope introduced by this statement -:535: var Scope* scope; -:536: /// Associated Symbol -:537: @@Semantic var Symbol* symbol; -:538: /// A token, used to dispatch to the visitors and to cast faster. -:539: var ExtendedTokenType kind; -:540: /// -:541: var bool containsNoReturn; -:542: /// -:543: @@Semantic var Flow flow; -:544: /// -:545: @override function free() -:546: { 4322:547: if scope do delete scope; 4215:548: super(); 4215:549: } -:550: /// -:551: @override function accept(AstVisitor* visitor) { assert(0); } -:552:} -:553: -:554:/// -:555:class Type : AstNode -:556:{ -:557: /// A token, used to dispatch to the visitors and to cast faster. -:558: var ExtendedTokenType kind; -:559: /// Indicates if the progress of the semantic analysis -:560: var SemanticProgress progress; -:561: /// Placeholder for the debug info -:562: @@Semantic var u8* dbgIr; -:563: /// The size in bit of a variable of this type -:564: var u32 size; -:565: /// -:566: var u32 align; -:567: /// 81367:568: @final @override function asType(): Type* {return this;} -:569: /// Returns: a symbol if this type is for a Declaration and `null` otherwise 84926:570: @virtual function asSymbol(): Symbol* { return null; } -:571: /// Returns: if the type is an integer 16204:572: @virtual function isIntegral(): bool { return false; } -:573: /// Returns: if the type is a float 48558:574: @virtual function isFloating(): bool { return false; } -:575: /// Returns: if the type is signed 91429:576: @virtual function isSigned(): bool { return false; } -:577: /// Returns: if the type is TypeIdentifier the type is resolves to and this otherwise 3039478:578: @virtual function resolved(): Type* { return this; } -:579: /// Returns: if a VariableDeclaration with this type is possible 14944:580: @virtual function isVariableType(): bool { return true; } -:581:} <<<<<< EOF # path=src/styx/ast/copier.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/ast/copier.sx -: 1:unit styx.ast.copier; -: 2: -: 3:@private import -: 4: styx.token, -: 5: styx.ast.base, -: 6: styx.ast.declarations, -: 7: styx.ast.expressions, -: 8: styx.ast.statements, -: 9: styx.ast.types, -: 10: styx.ast.visitor, -: 11: ; -: 12: -: 13:function copy(Declaration* source; bool skipGenericParameters): AstNode* -: 14:{ -: 15: var AstCopier copier; 238: 16: copier.skipGenericParameters = skipGenericParameters; 238: 17: copier.visitConcreteDeclaration(source); 238: 18: assert(copier.entryTarget); 238: 19: return copier.entryTarget; -: 20:} -: 21: -: 22:function copyGenericParameters(GenericParameters* source): AstNode* -: 23:{ -: 24: var AstCopier copier; 467: 25: copier.visitGenericParameters(source); 467: 26: assert(copier.entryTarget); 467: 27: return copier.entryTarget; -: 28:} -: 29: -: 30:function copyExpression(Expression* source; Expression** target) -: 31:{ -: 32: var AstCopier copier; 20: 33: copier.targetPtr = target:AstNode**; 20: 34: copier.visitExpression(source); 20: 35:} -: 36: -: 37:@private @final class AstCopier : AstVisitor -: 38:{ -: 39: var AstNode** targetPtr; -: 40: var AstNode* entryTarget; -: 41: var bool skipGenericParameters; -: 42: -: 43: static function copyCommonAggrFields(AggregateDeclaration* source; AggregateDeclaration* target) -: 44: { -: 45: var AstCopier copier; 112: 46: target.stopPos = source.stopPos; 224: 47: if const auto len = source.inheritanceList.length do -: 48: { 5: 49: target.inheritanceList.length = len; 5: 50: foreach (const auto i; var auto t) in source.inheritanceList[] do 5: 51: copier.setTargetPtr((&target.inheritanceList.ptr[i]):AstNode**).visitConcreteType(t); -: 52: } 112: 53: if source.body do 112: 54: copier.setTargetPtr((&target.body):AstNode**).visitDeclarations(source.body); 112: 55: } -: 56: -: 57: function copyCommonDeclFields(Declaration* source; Declaration* target) -: 58: { -: 59: var AstCopier copier; 814: 60: copier.skipGenericParameters = skipGenericParameters; 814: 61: if source.attributes do 118: 62: copier.setTargetPtr((&target.attributes):AstNode**).visitAttributes(source.attributes); 814: 63: if source.genericParameters do 244: 64: copier.setTargetPtr((&target.genericParameters):AstNode**).visitGenericParameters(source.genericParameters); 814: 65: target.$protection = source.$protection; 814: 66: target.stc = source.stc; 814: 67: target.name = source.name; 814: 68: } -: 69: -: 70: static function copyCommonFlowCtrlFields(FlowControl* source; FlowControl* target) -: 71: { -: 72: var AstCopier copier; 236: 73: target.stopPos = source.stopPos; 236: 74: if source.expression do 229: 75: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 236: 76: } -: 77: -: 78: static function processBinaryExp(BinaryExpression* source; BinaryExpression* target) -: 79: { -: 80: var AstCopier copier; 561: 81: copier.setTargetPtr((&target.left):AstNode**).visitExpression(source.left); 561: 82: if source.right do 560: 83: copier.setTargetPtr((&target.right):AstNode**).visitExpression(source.right); 561: 84: } -: 85: -: 86: static function processUnaryExp(UnaryExpression* source; UnaryExpression* target) -: 87: { -: 88: var AstCopier copier; 61: 89: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 61: 90: } -: 91: -: 92: function setTargetPtr(AstNode** node): AstCopier* -: 93: { 7477: 94: targetPtr = node; 7477: 95: return this; -: 96: } -: 97: -: 98: @override function visitAddAssignExpression(AddAssignExpression* source) -: 99: { 9: 100: var auto target = (new AddAssignExpression).create(source.startPos); 9: 101: processBinaryExp(source, target); 9: 102: *targetPtr = target; 9: 103: } -: 104: -: 105: @override function visitAddExpression(AddExpression* source) -: 106: { 71: 107: var auto target = (new AddExpression).create(source.startPos); 71: 108: processBinaryExp(source, target); 71: 109: *targetPtr = target; 71: 110: } -: 111: -: 112: @override function visitAliasDeclaration(AliasDeclaration* source) -: 113: { -: 114: var AstCopier copier; 12: 115: var auto target = (new AliasDeclaration).create(source.startPos); 12: 116: copyCommonDeclFields(source, target); 12: 117: if source.type do 4: 118: copier.setTargetPtr((&target.type):AstNode**).visitConcreteType(source.type); 8: 119: else do if source.exp do 8: 120: copier.setTargetPtr((&target.exp):AstNode**).visitExpression(source.exp); 12: 121: *targetPtr = target; 12: 122: } -: 123: -: 124: @override function visitAndAndExpression(AndAndExpression* source) -: 125: { 33: 126: var auto target = (new AndAndExpression).create(source.startPos); 33: 127: processBinaryExp(source, target); 33: 128: *targetPtr = target; 33: 129: } -: 130: -: 131: @override function visitAndAssignExpression(AndAssignExpression* source) -: 132: { 1: 133: var auto target = (new AndAssignExpression).create(source.startPos); 1: 134: processBinaryExp(source, target); 1: 135: *targetPtr = target; 1: 136: } -: 137: -: 138: @override function visitAndExpression(AndExpression* source) -: 139: { 1: 140: var auto target = (new AndExpression).create(source.startPos); 1: 141: processBinaryExp(source, target); 1: 142: *targetPtr = target; 1: 143: } -: 144: -: 145: @override function visitApplyExpression(ApplyExpression* source) -: 146: { -: 147: var AstCopier copier; 2: 148: var auto target = (new ApplyExpression).create(source.startPos, null, []); 2: 149: copier.setTargetPtr((&target.generic):AstNode**).visitExpression(source.generic); 2: 150: target.arguments.length = source.arguments.length; 2: 151: target.postStyle = source.postStyle; 2: 152: foreach (const auto i; var auto a) in source.arguments do 2: 153: copier.setTargetPtr((&target.arguments.ptr[i]):AstNode**).visitExpression(a); 2: 154: *targetPtr = target; 2: 155: } -: 156: -: 157: @override function visitArrayExpression(ArrayExpression* source) -: 158: { -: 159: var AstCopier copier; 2: 160: var auto target = (new ArrayExpression).create(source.startPos); 4: 161: if const auto len = source.items.length do -: 162: { 2: 163: target.items.length = len; 2: 164: foreach (const auto i; var auto e) in source.items[] do 5: 165: copier.setTargetPtr((&target.items.ptr[i]):AstNode**).visitExpression(e); -: 166: } 2: 167: *targetPtr = target; 2: 168: } -: 169: -: 170: @override function visitAssertStatement(AssertStatement* source) -: 171: { -: 172: var AstCopier copier; 32: 173: var auto target = (new AssertStatement).create(source.startPos); 32: 174: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 32: 175: if source.message do 2: 176: copier.setTargetPtr((&target.message):AstNode**).visitExpression(source.message); 32: 177: target.isStatic = source.isStatic; 32: 178: *targetPtr = target; 32: 179: } -: 180: -: 181: @override function visitAssignExpression(AssignExpression* source) -: 182: { 79: 183: var auto target = (new AssignExpression).create(source.startPos); 79: 184: processBinaryExp(source, target); 79: 185: *targetPtr = target; 79: 186: } -: 187: -: 188: @override function visitAsmExpression(AsmExpression* source) -: 189: { -: 190: var AstCopier copier; 1: 191: var auto target = (new AsmExpression).create(source.startPos); 1: 192: target.code = source.code; 1: 193: target.constraint = source.constraint; 2: 194: if const auto aLen = source.arguments.length do -: 195: { 1: 196: target.arguments.length = aLen; 1: 197: foreach (const auto i; var auto a) in source.arguments do 1: 198: copier.setTargetPtr((&target.arguments.ptr[i]):AstNode**).visitExpression(a); -: 199: } 1: 200: if source.returnType do 1: 201: copier.setTargetPtr((&target.returnType):AstNode**).visitConcreteType(source.returnType); 1: 202: *targetPtr = target; 1: 203: } -: 204: -: 205: @override function visitAtExpression(AtExpression* source) -: 206: { 5: 207: var auto target = (new AtExpression).create(source.startPos); 5: 208: processUnaryExp(source, target); 5: 209: *targetPtr = target; 5: 210: } -: 211: -: 212: @override function visitAttribute(Attribute* source) -: 213: { -: 214: var AstCopier copier; 42: 215: var auto target = (new Attribute).create(source.startPos, source.identifier, source.isUser); 42: 216: target.arguments.length = source.arguments.length; 42: 217: foreach (const auto i; var auto a) in source.arguments do 44: 218: copier.setTargetPtr((&target.arguments.ptr[i]):AstNode**).visitExpression(a); 42: 219: *targetPtr = target; 42: 220: } -: 221: -: 222: @override function visitAttributes(Attributes* source) -: 223: { -: 224: var AstCopier copier; 118: 225: var auto target = (new Attributes).create(source.startPos); -: 226: alias t = target; -: 227: alias s = source; 118: 228: var auto tAttribs = [&t.atAsm, &t.atDeprecated, &t.atForeign, &t.atInline, &t.atLLVM, -: 229: &t.atOperator, &t.atOverload, &t.atProtection, &t.atUnittest]; 118: 230: var auto sAttribs = [ s.atAsm, s.atDeprecated, s.atForeign, s.atInline, s.atLLVM, -: 231: s.atOperator, s.atOverload, s.atProtection, s.atUnittest]; 118: 232: foreach const auto i in 0 .. tAttribs.length do -: 233: { 1062: 234: var auto sa = sAttribs[i]; 1062: 235: if !sa do 1004: 236: continue; 58: 237: if !sa.arguments do 18: 238: continue *tAttribs.ptr[i] = sa; 40: 239: copier.setTargetPtr((tAttribs.ptr[i]):AstNode**).visitAttribute(sa); -: 240: } 118: 241: target.noArgAttributes = source.noArgAttributes; 236: 242: if const auto uLen = source.atUser.length do -: 243: { 2: 244: target.atUser.length = uLen; 2: 245: foreach (const auto i; const auto a) in source.atUser[] do -: 246: { 4: 247: if !a.arguments do 2: 248: continue target.atUser.ptr[i] = a; 2: 249: copier.setTargetPtr((&target.atUser.ptr[i]):AstNode**).visitAttribute(a); -: 250: } -: 251: } 118: 252: *targetPtr = target; 118: 253: } -: 254: -: 255: @override function visitBlockStatement(BlockStatement* source) -: 256: { -: 257: var AstCopier copier; 499: 258: var auto target = (new BlockStatement).create(source.startPos); 499: 259: target.statements.length = source.statements.length; 499: 260: foreach (const auto i; var auto s) in source.statements do 873: 261: copier.setTargetPtr((&target.statements.ptr[i]):AstNode**).visitConcreteStatement(s); 499: 262: target.isSingle = source.isSingle; 499: 263: target.noScope = source.noScope; 499: 264: target.stopPos = source.stopPos; 499: 265: *targetPtr = target; 499: 266: } -: 267: -: 268: @override function visitBoolExpression(BoolExpression* source) -: 269: { 11: 270: *targetPtr = (new BoolExpression).create(source.startPos, source.tok, source.value != 0); 11: 271: } -: 272: -: 273: @override function visitBreakOnStatement(BreakOnStatement* source) -: 274: { 1: 275: var auto target = (new BreakOnStatement).create(source.startPos); 1: 276: copyCommonFlowCtrlFields(source, target); 1: 277: *targetPtr = target; 1: 278: } -: 279: -: 280: @override function visitBreakStatement(BreakStatement* source) -: 281: { 2: 282: var auto target = (new BreakStatement).create(source.startPos); 2: 283: copyCommonFlowCtrlFields(source, target); 2: 284: target.$label = source.$label; 2: 285: *targetPtr = target; 2: 286: } -: 287: -: 288: @override function visitCallExpression(CallExpression* source) -: 289: { -: 290: var AstCopier copier; 209: 291: var CallExpression* target = (new CallExpression).create(source.startPos); 209: 292: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 418: 293: if const auto aLen = source.arguments.length do -: 294: { 108: 295: target.arguments.length = aLen; 108: 296: foreach (const auto i; var auto a) in source.arguments do 141: 297: copier.setTargetPtr((&target.arguments.ptr[i]):AstNode**).visitExpression(a); -: 298: } 209: 299: *targetPtr = target; 209: 300: } -: 301: -: 302: @override function visitCastExpression(CastExpression* source) -: 303: { -: 304: var AstCopier copier; 73: 305: var CastExpression* target = (new CastExpression).create(source.startPos); 73: 306: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 73: 307: copier.setTargetPtr((&target.toType):AstNode**).visitConcreteType(source.toType); 73: 308: *targetPtr = target; 73: 309: } -: 310: -: 311: @override function visitClassDeclaration(ClassDeclaration* source) -: 312: { 13: 313: if !source do return; -: 314: 13: 315: var auto target = (new ClassDeclaration).create(source.startPos); 13: 316: entryTarget ?= target; -: 317: 13: 318: copyCommonDeclFields(source, target); 13: 319: copyCommonAggrFields(source, target); -: 320: 17: 321: if targetPtr do *targetPtr = target; 13: 322: } -: 323: -: 324: @override function visitCmpExpression(CmpExpression* source) -: 325: { 185: 326: var auto target = (new CmpExpression).create(source.startPos, source.operator); 185: 327: processBinaryExp(source, target); 185: 328: *targetPtr = target; 185: 329: } -: 330: -: 331: @override function visitConcatAssignExpression(ConcatAssignExpression* source) -: 332: { 9: 333: var auto target = (new ConcatAssignExpression).create(source.startPos); 9: 334: processBinaryExp(source, target); 9: 335: *targetPtr = target; 9: 336: } -: 337: -: 338: @override function visitConcatExpression(ConcatExpression* source) -: 339: { 1: 340: var auto target = (new ConcatExpression).create(source.startPos); 1: 341: processBinaryExp(source, target); 1: 342: *targetPtr = target; 1: 343: } -: 344: -: 345: @override function visitConditionalExpression(ConditionalExpression* source) -: 346: { -: 347: var AstCopier copier; 7: 348: var auto target = (new ConditionalExpression).create(source.startPos); 7: 349: copier.setTargetPtr((&target.condition):AstNode**).visitExpression(source.condition); 7: 350: copier.setTargetPtr((&target.thenExpression):AstNode**).visitExpression(source.thenExpression); 7: 351: if source.elseExpression do 5: 352: copier.setTargetPtr((&target.elseExpression):AstNode**).visitExpression(source.elseExpression); 7: 353: target.isShorthandSyntax = source.isShorthandSyntax; 7: 354: *targetPtr = target; 7: 355: } -: 356: -: 357: @override function visitContinueOnStatement(ContinueOnStatement* source) -: 358: { 1: 359: var auto target = (new ContinueOnStatement).create(source.startPos); 1: 360: copyCommonFlowCtrlFields(source, target); 1: 361: if source.targetMatch do -: 362: { -: 363: var AstCopier copier; 1: 364: copier.setTargetPtr((&target.targetMatch):AstNode**).visitExpression(source.targetMatch); -: 365: } 1: 366: *targetPtr = target; 1: 367: } -: 368: -: 369: @override function visitContinueStatement(ContinueStatement* source) -: 370: { 2: 371: var auto target = (new ContinueStatement).create(source.startPos); 2: 372: copyCommonFlowCtrlFields(source, target); 2: 373: target.$label = source.$label; 2: 374: *targetPtr = target; 2: 375: } -: 376: -: 377: @override function visitDeclarationStatement(DeclarationStatement* source) -: 378: { -: 379: var AstCopier copier; 188: 380: var auto target = (new DeclarationStatement).create(source.startPos); 188: 381: copier.setTargetPtr((&target.declaration):AstNode**).visitConcreteDeclaration(source.declaration); 188: 382: *targetPtr = target; 188: 383: } -: 384: -: 385: @override function visitDeclarations(Declarations* source) -: 386: { 114: 387: if !source do return; -: 388: -: 389: var AstCopier copier; 114: 390: var auto target = (new Declarations).create(source.startPos); 114: 391: target.items.length = source.items.length; -: 392: 114: 393: foreach (const auto i; var auto d) in source.items[] do 214: 394: copier.setTargetPtr((&target.items.ptr[i]):AstNode**).visitConcreteDeclaration(d); -: 395: 114: 396: *targetPtr = target; 114: 397: } -: 398: -: 399: @override function visitDeleteExpression(DeleteExpression* source) -: 400: { -: 401: var AstCopier copier; 34: 402: var auto target = (new DeleteExpression).create(source.startPos); 34: 403: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 34: 404: if source.deallocator do 1: 405: copier.setTargetPtr((&target.deallocator):AstNode**).visitExpression(source.deallocator); 34: 406: *targetPtr = target; 34: 407: } -: 408: -: 409: @override function visitDerefExpression(DerefExpression* source) -: 410: { 1: 411: var auto target = (new DerefExpression).create(source.startPos); 1: 412: processUnaryExp(source, target); 1: 413: *targetPtr = target; 1: 414: } -: 415: -: 416: @override function visitDivAssignExpression(DivAssignExpression* source) -: 417: { 1: 418: var auto target = (new DivAssignExpression).create(source.startPos); 1: 419: processBinaryExp(source, target); 1: 420: *targetPtr = target; 1: 421: } -: 422: -: 423: @override function visitDivExpression(DivExpression* source) -: 424: { 1: 425: var auto target = (new DivExpression).create(source.startPos); 1: 426: processBinaryExp(source, target); 1: 427: *targetPtr = target; 1: 428: } -: 429: -: 430: @override function visitDollarExpression(DollarExpression* source) -: 431: { 4: 432: *targetPtr = (new DollarExpression).create(source.startPos); 4: 433: } -: 434: -: 435: @override function visitDotExpression(DotExpression* source) -: 436: { -: 437: var AstCopier copier; 201: 438: var auto target = (new DotExpression).create(source.startPos, null, null); 201: 439: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 201: 440: copier.setTargetPtr((&target.dotted):AstNode**).visitExpression(source.dotted); 201: 441: *targetPtr = target; 201: 442: } -: 443: -: 444: @override function visitEchoExpression(EchoExpression* source) -: 445: { 54: 446: var auto target = (new EchoExpression).create(source.startPos, source.command); 108: 447: if const auto aLen = source.arguments.length do -: 448: { -: 449: var AstCopier copier; 54: 450: target.arguments.length = aLen; 54: 451: foreach (const auto i ; var auto a) in source.arguments do 92: 452: copier.setTargetPtr((&target.arguments.ptr[i]):AstNode**).visitExpression(a); -: 453: } 54: 454: *targetPtr = target; 54: 455: } -: 456: -: 457: @override function visitEnumDeclaration(EnumDeclaration* source) -: 458: { -: 459: var AstCopier copier; 2: 460: var auto target = (new EnumDeclaration).create(source.startPos); 2: 461: copyCommonDeclFields(source, target); 2: 462: if source.type do 1: 463: copier.setTargetPtr((&target.type):AstNode**).visitConcreteType(source.type); 2: 464: target.flags = source.flags; 2: 465: target.members.length = source.members.length; 2: 466: foreach (const auto i; var auto m) in source.members do 3: 467: copier.setTargetPtr((&target.members.ptr[i]):AstNode**).visitEnumMember(m); 2: 468: *targetPtr = target; 2: 469: } -: 470: -: 471: @override function visitEnumMember(EnumMember* source) -: 472: { -: 473: var AstCopier copier; 3: 474: var auto target = (new EnumMember).create(source.startPos, null); 3: 475: copyCommonDeclFields(source, target); 3: 476: if source.value do 1: 477: copier.setTargetPtr((&target.value):AstNode**).visitExpression(source.value); 3: 478: *targetPtr = target; 3: 479: } -: 480: -: 481: @override function visitExpression(Expression* source) -: 482: { 3281: 483: visitConcreteExpression(source); 3281: 484: (*((targetPtr):Expression**)).parens = source.parens; 3281: 485: } -: 486: -: 487: @override function visitExpressionAlias(ExpressionAlias* source) -: 488: { -: 489: var AstCopier copier; 1: 490: var auto target = (new ExpressionAlias).create(source.startPos, null, null); 1: 491: copyCommonDeclFields(source, target); 1: 492: if source.expression do 1: 493: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 1: 494: *targetPtr = target; 1: 495: } -: 496: -: 497: @override function visitExpressionStatement(ExpressionStatement* source) -: 498: { -: 499: var AstCopier copier; 213: 500: var auto target = (new ExpressionStatement).create(source.startPos, null); 213: 501: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 213: 502: *targetPtr = target; 213: 503: } -: 504: -: 505: @override function visitForeachStatement(ForeachStatement* source) -: 506: { -: 507: var AstCopier copier; 29: 508: var auto target = (new ForeachStatement).create(source.startPos); 29: 509: target.variables.length = source.variables.length; 29: 510: foreach (const auto i; var auto v) in source.variables do 49: 511: copier.setTargetPtr((&target.variables.ptr[i]):AstNode**).visitVariableDeclaration(v); 29: 512: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 29: 513: copier.setTargetPtr((&target.blockStatement):AstNode**).visitBlockStatement(source.blockStatement); 29: 514: target.hasParens = source.hasParens; 29: 515: *targetPtr = target; 29: 516: } -: 517: -: 518: @override function visitFloatExpression(FloatExpression* source) -: 519: { 2: 520: *targetPtr = (new FloatExpression).create(source.startPos, source.tok); 2: 521: } -: 522: -: 523: @override function visitFunctionDeclaration(FunctionDeclaration* source) -: 524: { -: 525: var AstCopier copier; 261: 526: var auto target = (new FunctionDeclaration).create(source.startPos); 261: 527: entryTarget ?= target; -: 528: 261: 529: copyCommonDeclFields(source, target); 261: 530: copier.setTargetPtr((&target.returnType):AstNode**).visitConcreteType(source.returnType); -: 531: -: 532: // if present, dont copy the implicit `this` parameter as the AST will be re-symbolized 261: 533: const u8 offs = source.parameters.length && implicitThis in source.parameters[0].flags; 261: 534: target.parameters.length = source.parameters.length - offs; 261: 535: foreach (const auto i; var auto p) in source.parameters[offs .. $] do 126: 536: copier.setTargetPtr((&target.parameters.ptr[i]):AstNode**).visitVariableDeclaration(p); -: 537: 261: 538: if source.body do 253: 539: copier.setTargetPtr((&target.body):AstNode**).visitConcreteStatement(source.body); 261: 540: if source.asmBody do 1: 541: copier.setTargetPtr((&target.asmBody):AstNode**).visitExpression(source.asmBody); -: 542: 261: 543: target.stopPos = source.stopPos; -: 544: 383: 545: if targetPtr do *targetPtr = target; 261: 546: } -: 547: -: 548: @override function visitGotoStatement(GotoStatement* source) -: 549: { 1: 550: var auto target = (new GotoStatement).create(source.startPos); 1: 551: copyCommonFlowCtrlFields(source, target); 1: 552: target.$label = source.$label; 1: 553: *targetPtr = target; 1: 554: } -: 555: -: 556: @override function visitIdentExpression(IdentExpression* source) -: 557: { 1673: 558: *targetPtr = (new IdentExpression).create(source.startPos, source.identifier); 1673: 559: } -: 560: -: 561: @override function visitIfElseStatement(IfElseStatement* source) -: 562: { -: 563: var AstCopier copier; 174: 564: var auto target = (new IfElseStatement).create(source.startPos); 174: 565: if source.ifVariable do 1: 566: copier.setTargetPtr((&target.ifVariable):AstNode**).visitVariableDeclaration(source.ifVariable); 174: 567: if source.condition do 173: 568: copier.setTargetPtr((&target.condition):AstNode**).visitExpression(source.condition); 174: 569: if source.thenBlock do 174: 570: copier.setTargetPtr((&target.thenBlock):AstNode**).visitBlockStatement(source.thenBlock); 174: 571: if source.elseBlock do 31: 572: copier.setTargetPtr((&target.elseBlock):AstNode**).visitBlockStatement(source.elseBlock); 174: 573: *targetPtr = target; 174: 574: } -: 575: -: 576: @override function visitImportDeclaration(ImportDeclaration* source) -: 577: { -: 578: var AstCopier copier; 1: 579: var auto target = (new ImportDeclaration).create(source.startPos); 1: 580: target.isSelective = source.isSelective; 1: 581: target.importList.length = source.importList.length; 1: 582: foreach (const auto i; var auto imp) in source.importList[] do 1: 583: copier.setTargetPtr((&target.importList.ptr[i]):AstNode**).visitConcreteType(imp); 1: 584: *targetPtr = target; 1: 585: } -: 586: -: 587: @override function visitInExpression(InExpression* source) -: 588: { 6: 589: var auto target = (new InExpression).create(source.startPos); 6: 590: processBinaryExp(source, target); 6: 591: target.negated = source.negated; 6: 592: *targetPtr = target; 6: 593: } -: 594: -: 595: @override function visitIndexExpression(IndexExpression* source) -: 596: { -: 597: var AstCopier copier; 68: 598: var auto target = (new IndexExpression).create(source.startPos, null, null, null); 68: 599: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 68: 600: target.indexes.length = source.indexes.length; 68: 601: foreach (const auto i; var auto e) in source.indexes do 68: 602: copier.setTargetPtr((&target.indexes.ptr[i]):AstNode**).visitExpression(e); 68: 603: *targetPtr = target; 68: 604: } -: 605: -: 606: @override function visitIntegerExpression(IntegerExpression* source) -: 607: { 232: 608: *targetPtr = (new IntegerExpression).create(source.startPos, source.tok); 232: 609: } -: 610: -: 611: @override function visitGenericParameters(GenericParameters* source) -: 612: { 711: 613: if !source || skipGenericParameters do -: 614: { -: 615: // only skip for entry decl params 238: 616: skipGenericParameters = false; 238: 617: return; -: 618: } -: 619: -: 620: var AstCopier copier; 473: 621: var auto target = new GenericParameters; 473: 622: entryTarget ?= target; 473: 623: target.parameters.length = source.parameters.length; -: 624: 473: 625: foreach (const auto i; var auto p) in source.parameters[] do 680: 626: copier.setTargetPtr((&target.parameters.ptr[i]):AstNode**).visitGenericParameter(p); -: 627: 479: 628: if targetPtr do *targetPtr = target; 473: 629: } -: 630: -: 631: @override function visitGenericParameter(GenericParameter* source) -: 632: { 680: 633: if !source do return; -: 634: 680: 635: var auto target = (new GenericParameter).create(source.startPos, source.name, source.valueType); -: 636: -: 637: // keep existing generic application as-is 680: 638: target.appliedExp = source.appliedExp; 680: 639: target.appliedType = source.appliedType; -: 640: 680: 641: *targetPtr = target; 680: 642: } -: 643: -: 644: @override function visitLShiftAssignExpression(LShiftAssignExpression* source) -: 645: { 1: 646: var auto target = (new LShiftAssignExpression).create(source.startPos); 1: 647: processBinaryExp(source, target); 1: 648: *targetPtr = target; 1: 649: } -: 650: -: 651: @override function visitLShiftExpression(LShiftExpression* source) -: 652: { 1: 653: var auto target = (new LShiftExpression).create(source.startPos); 1: 654: processBinaryExp(source, target); 1: 655: *targetPtr = target; 1: 656: } -: 657: -: 658: @override function visitLabelDeclaration(LabelDeclaration* source) -: 659: { 1: 660: var auto target = (new LabelDeclaration).create(source.startPos); 1: 661: copyCommonDeclFields(source, target); 1: 662: *targetPtr = target; 1: 663: } -: 664: -: 665: @override function visitLambdaExpression(LambdaExpression* source) -: 666: { -: 667: var AstCopier copier; 1: 668: var auto target = (new LambdaExpression).create(source.startPos, null, source.bodyAsExp); 1: 669: copier.setTargetPtr((&target.func):AstNode**).visitFunctionDeclaration(source.func); 1: 670: *targetPtr = target; 1: 671: } -: 672: -: 673: @override function visitModAssignExpression(ModAssignExpression* source) -: 674: { 1: 675: var auto target = (new ModAssignExpression).create(source.startPos); 1: 676: processBinaryExp(source, target); 1: 677: *targetPtr = target; 1: 678: } -: 679: -: 680: @override function visitModExpression(ModExpression* source) -: 681: { 1: 682: var auto target = (new ModExpression).create(source.startPos); 1: 683: processBinaryExp(source, target); 1: 684: *targetPtr = target; 1: 685: } -: 686: -: 687: @override function visitMulAssignExpression(MulAssignExpression* source) -: 688: { 1: 689: var auto target = (new MulAssignExpression).create(source.startPos); 1: 690: processBinaryExp(source, target); 1: 691: *targetPtr = target; 1: 692: } -: 693: -: 694: @override function visitMulExpression(MulExpression* source) -: 695: { 21: 696: var auto target = (new MulExpression).create(source.startPos); 21: 697: processBinaryExp(source, target); 21: 698: *targetPtr = target; 21: 699: } -: 700: -: 701: @override function visitNegExpression(NegExpression* source) -: 702: { 3: 703: var auto target = (new NegExpression).create(source.startPos); 3: 704: processUnaryExp(source, target); 3: 705: *targetPtr = target; 3: 706: } -: 707: -: 708: @override function visitNewExpression(NewExpression* source) -: 709: { -: 710: var AstCopier copier; 29: 711: var auto target = (new NewExpression).create(source.startPos); 29: 712: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 29: 713: if source.allocator do 1: 714: copier.setTargetPtr((&target.allocator):AstNode**).visitExpression(source.allocator); 29: 715: *targetPtr = target; 29: 716: } -: 717: -: 718: @override function visitNotExpression(NotExpression* source) -: 719: { 24: 720: var auto target = (new NotExpression).create(source.startPos); 24: 721: processUnaryExp(source, target); 24: 722: *targetPtr = target; 24: 723: } -: 724: -: 725: @override function visitNullExpression(NullExpression* source) -: 726: { 4: 727: *targetPtr = (new NullExpression).create(source.startPos); 4: 728: } -: 729: -: 730: @override function visitOneCompExpression(OneCompExpression* source) -: 731: { 1: 732: var auto target = (new OneCompExpression).create(source.startPos); 1: 733: processUnaryExp(source, target); 1: 734: *targetPtr = target; 1: 735: } -: 736: -: 737: @override function visitOnMatchStatement(OnMatchStatement* source) -: 738: { -: 739: var AstCopier copier; 4: 740: var auto target = (new OnMatchStatement).create(source.startPos); 4: 741: copier.setTargetPtr((&target.blockStatement):AstNode**).visitBlockStatement(source.blockStatement); 4: 742: target.onMatchExpressions.length = source.onMatchExpressions.length; 4: 743: foreach (const auto i; var auto ome) in source.onMatchExpressions do 4: 744: copier.setTargetPtr((&target.onMatchExpressions.ptr[i]):AstNode**).visitExpression(ome); 4: 745: *targetPtr = target; 4: 746: } -: 747: -: 748: @override function visitOptAccessExpression(OptAccessExpression* source) -: 749: { 1: 750: var auto target = (new OptAccessExpression).create(source.startPos); 1: 751: processUnaryExp(source, target); 1: 752: *targetPtr = target; 1: 753: } -: 754: -: 755: @override function visitOptAssignExpression(OptAssignExpression* source) -: 756: { 31: 757: var auto target = (new OptAssignExpression).create(source.startPos); 31: 758: processBinaryExp(source, target); 31: 759: *targetPtr = target; 31: 760: } -: 761: -: 762: @override function visitOrAssignExpression(OrAssignExpression* source) -: 763: { 1: 764: var auto target = (new OrAssignExpression).create(source.startPos); 1: 765: processBinaryExp(source, target); 1: 766: *targetPtr = target; 1: 767: } -: 768: -: 769: @override function visitOrExpression(OrExpression* source) -: 770: { 1: 771: var auto target = (new OrExpression).create(source.startPos); 1: 772: processBinaryExp(source, target); 1: 773: *targetPtr = target; 1: 774: } -: 775: -: 776: @override function visitOrOrExpression(OrOrExpression* source) -: 777: { 33: 778: var auto target = (new OrOrExpression).create(source.startPos); 33: 779: processBinaryExp(source, target); 33: 780: *targetPtr = target; 33: 781: } -: 782: -: 783: @override function visitOverloadDeclaration(OverloadDeclaration* source) -: 784: { -: 785: var AstCopier copier; 2: 786: var auto target = (new OverloadDeclaration).create(source.startPos); 2: 787: copyCommonDeclFields(source, target); 2: 788: if source.base do 1: 789: copier.setTargetPtr((&target.base):AstNode**).visitConcreteType(source.base); 2: 790: target.members.length = source.members.length; 2: 791: foreach (const auto i; var auto m) in source.members do 2: 792: copier.setTargetPtr((&target.members.ptr[i]):AstNode**).visitExpression(m); 2: 793: *targetPtr = target; 2: 794: } -: 795: -: 796: @override function visitPostDecExpression(PostDecExpression* source) -: 797: { 3: 798: var auto target = (new PostDecExpression).create(source.startPos); 3: 799: processUnaryExp(source, target); 3: 800: *targetPtr = target; 3: 801: } -: 802: -: 803: @override function visitPostIncExpression(PostIncExpression* source) -: 804: { 19: 805: var auto target = (new PostIncExpression).create(source.startPos); 19: 806: processUnaryExp(source, target); 19: 807: *targetPtr = target; 19: 808: } -: 809: -: 810: @override function visitPreDecExpression(PreDecExpression* source) -: 811: { 1: 812: var auto target = (new PreDecExpression).create(source.startPos); 1: 813: processUnaryExp(source, target); 1: 814: *targetPtr = target; 1: 815: } -: 816: -: 817: @override function visitPreIncExpression(PreIncExpression* source) -: 818: { 3: 819: var auto target = (new PreIncExpression).create(source.startPos); 3: 820: processUnaryExp(source, target); 3: 821: *targetPtr = target; 3: 822: } -: 823: -: 824: @override function visitProtectionDeclaration(ProtectionDeclaration* source) -: 825: { 4: 826: *targetPtr = (new ProtectionDeclaration).create(source.startPos, source.$protection); 4: 827: } -: 828: -: 829: @override function visitRShiftAssignExpression(RShiftAssignExpression* source) -: 830: { 1: 831: var auto target = (new RShiftAssignExpression).create(source.startPos); 1: 832: processBinaryExp(source, target); 1: 833: *targetPtr = target; 1: 834: } -: 835: -: 836: @override function visitRShiftExpression(RShiftExpression* source) -: 837: { 1: 838: var auto target = (new RShiftExpression).create(source.startPos); 1: 839: processBinaryExp(source, target); 1: 840: *targetPtr = target; 1: 841: } -: 842: -: 843: @override function visitRangeExpression(RangeExpression* source) -: 844: { 20: 845: var auto target = (new RangeExpression).create(source.startPos); 20: 846: processBinaryExp(source, target); 20: 847: *targetPtr = target; 20: 848: } -: 849: -: 850: @override function visitReturnStatement(ReturnStatement* source) -: 851: { 229: 852: var auto target = (new ReturnStatement).create(source.startPos); 229: 853: copyCommonFlowCtrlFields(source, target); 229: 854: *targetPtr = target; 229: 855: } -: 856: -: 857: @override function visitSliceExpression(SliceExpression* source) -: 858: { -: 859: var AstCopier copier; 32: 860: var auto target = (new SliceExpression).create(source.startPos, null); 32: 861: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 32: 862: if source.range do 18: 863: copier.setTargetPtr((&target.range):AstNode**).visitRangeExpression(source.range); 32: 864: target.tryAsTypeRca = source.tryAsTypeRca; 32: 865: *targetPtr = target; 32: 866: } -: 867: -: 868: @override function visitStaticAssertDeclaration(StaticAssertDeclaration* source) -: 869: { -: 870: var AstCopier copier; 8: 871: var auto target = (new StaticAssertDeclaration).create(source.startPos); 8: 872: copier.setTargetPtr((&target.assertion):AstNode**).visitConcreteStatement(source.assertion); 8: 873: *targetPtr = target; 8: 874: } -: 875: -: 876: @override function visitStringExpression(StringExpression* source) -: 877: { 14: 878: *targetPtr = (new StringExpression).create(source.startPos, source.value); 14: 879: } -: 880: -: 881: @override function visitStructDeclaration(StructDeclaration* source) -: 882: { 97: 883: if !source do return; -: 884: 97: 885: var auto target = (new StructDeclaration).create(source.startPos); 97: 886: entryTarget ?= target; -: 887: 97: 888: copyCommonDeclFields(source, target); 97: 889: copyCommonAggrFields(source, target); -: 890: 106: 891: if targetPtr do *targetPtr = target; 97: 892: } -: 893: -: 894: @override function visitSubAssignExpression(SubAssignExpression* source) -: 895: { 2: 896: var auto target = (new SubAssignExpression).create(source.startPos); 2: 897: processBinaryExp(source, target); 2: 898: *targetPtr = target; 2: 899: } -: 900: -: 901: @override function visitSubExpression(SubExpression* source) -: 902: { 46: 903: var auto target = (new SubExpression).create(source.startPos); 46: 904: processBinaryExp(source, target); 46: 905: *targetPtr = target; 46: 906: } -: 907: -: 908: @override function visitSuperExpression(SuperExpression* source) -: 909: { 1: 910: *targetPtr = (new SuperExpression).create(source.startPos); 1: 911: } -: 912: -: 913: @override function visitSwitchStatement(SwitchStatement* source) -: 914: { -: 915: var AstCopier copier; 3: 916: var auto target = (new SwitchStatement).create(source.startPos); 3: 917: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 3: 918: if source.elseBlock do 2: 919: copier.setTargetPtr((&target.elseBlock):AstNode**).visitBlockStatement(source.elseBlock); 3: 920: target.onMatchStatements.length = source.onMatchStatements.length; 3: 921: foreach (const auto i; var auto oms) in source.onMatchStatements do 4: 922: copier.setTargetPtr((&target.onMatchStatements.ptr[i]):AstNode**).visitOnMatchStatement(oms); 3: 923: *targetPtr = target; 3: 924: } -: 925: -: 926: @override function visitThisExpression(ThisExpression* source) -: 927: { 1: 928: *targetPtr = (new ThisExpression).create(source.startPos); 1: 929: } -: 930: -: 931: @override function visitTupleExpression(TupleExpression* source) -: 932: { -: 933: var AstCopier copier; 2: 934: var auto target = (new TupleExpression).create(source.startPos, []); 2: 935: target.expressions.length = source.expressions.length; 2: 936: foreach (const auto i; var auto e) in source.expressions do 5: 937: copier.setTargetPtr((&target.expressions.ptr[i]):AstNode**).visitExpression(e); 2: 938: *targetPtr = target; 2: 939: } -: 940: -: 941: @override function visitTypeAppliedGeneric(TypeAppliedGeneric* source) -: 942: { -: 943: assert(0); -: 944: } -: 945: -: 946: @override function visitTypeAuto(TypeAuto* source) -: 947: { 143: 948: *targetPtr = source; 143: 949: } -: 950: -: 951: @override function visitTypeBool(TypeBool* source) -: 952: { 45: 953: *targetPtr = source; 45: 954: } -: 955: -: 956: @override function visitTypeEcho(TypeEcho* source) -: 957: { -: 958: var AstCopier copier; 2: 959: var auto target = (new TypeEcho).create(null); 2: 960: copier.setTargetPtr((&target.expression):AstNode**).visitExpression(source.expression); 2: 961: *targetPtr = source; 2: 962: } -: 963: -: 964: @override function visitTypeElements(TypeElements* source) -: 965: { -: 966: var AstCopier copier; 1: 967: var auto target = (new TypeElements).create(null, []); 1: 968: target.isSlice = source.isSlice; 1: 969: copier.setTargetPtr((&target.elements):AstNode**).visitConcreteType(source.elements); 1: 970: target.indexes.length = source.indexes.length; 1: 971: foreach (const auto i; var auto e) in source.indexes do 2: 972: copier.setTargetPtr((&target.indexes.ptr[i]):AstNode**).visitExpression(e); 1: 973: *targetPtr = target; 1: 974: } -: 975: -: 976: @override function visitTypeExpression(TypeExpression* source) -: 977: { -: 978: var AstCopier copier; 20: 979: var auto target = (new TypeExpression).create(source.startPos); 20: 980: copier.setTargetPtr((&target.wrapped):AstNode**).visitConcreteType(source.wrapped); 20: 981: target.raw = source.raw; 20: 982: *targetPtr = target; 20: 983: } -: 984: -: 985: @override function visitTypeF32(TypeF32* source) -: 986: { 1: 987: *targetPtr = source; 1: 988: } -: 989: -: 990: @override function visitTypeF64(TypeF64* source) -: 991: { 2: 992: *targetPtr = source; 2: 993: } -: 994: -: 995: @override function visitTypeFunction(TypeFunction* source) -: 996: { -: 997: var AstCopier copier; 7: 998: var auto target = (new TypeFunction).create(null, false); 7: 999: copier.setTargetPtr((&target.declaration):AstNode**).visitFunctionDeclaration(source.declaration); 7:1000: target.TypeDeclared.declaration = target.declaration; 7:1001: target.ownDeclaration = source.ownDeclaration; 7:1002: *targetPtr = target; 7:1003: } -:1004: -:1005: @override function visitTypeIdentifier(TypeIdentifier* source) -:1006: { 251:1007: var auto target = (new TypeIdentifier).create(source.identifier); 251:1008: target.startPos = source.startPos; -:1009: var AstCopier copier; 251:1010: if source.next do 2:1011: copier.setTargetPtr((&target.next):AstNode**).visitTypeIdentifier(source.next); 251:1012: target.genericArguments.length = source.genericArguments.length; 251:1013: foreach (const auto i; var auto a) in source.genericArguments do 4:1014: copier.setTargetPtr((&target.genericArguments.ptr[i]):AstNode**).visitExpression(a); 251:1015: *targetPtr = target; 251:1016: } -:1017: -:1018: @override function visitTypeNull(TypeNull* source) -:1019: { -:1020: assert(0, "add this case to the test suite"); -:1021: } -:1022: -:1023: @override function visitTypePointer(TypePointer* source) -:1024: { -:1025: var AstCopier copier; 139:1026: var auto target = (new TypePointer).create(null); 139:1027: copier.setTargetPtr((&target.modified):AstNode**).visitConcreteType(source.modified); -:1028: 139:1029: *targetPtr = target; 139:1030: } -:1031: -:1032: @override function visitTypeRcArray(TypeRcArray* source) -:1033: { -:1034: var AstCopier copier; 26:1035: var auto target = (new TypeRcArray).create(null); 26:1036: copier.setTargetPtr((&target.modified):AstNode**).visitConcreteType(source.modified); -:1037: 26:1038: *targetPtr = target; 26:1039: } -:1040: -:1041: @override function visitTypeS16(TypeS16* source) -:1042: { 1:1043: *targetPtr = source; 1:1044: } -:1045: -:1046: @override function visitTypeS32(TypeS32* source) -:1047: { 54:1048: *targetPtr = source; 54:1049: } -:1050: -:1051: @override function visitTypeS64(TypeS64* source) -:1052: { 6:1053: *targetPtr = source; 6:1054: } -:1055: -:1056: @override function visitTypeS8(TypeS8* source) -:1057: { 53:1058: *targetPtr = source; 53:1059: } -:1060: -:1061: @override function visitTypeSlice(TypeSlice* source) -:1062: { -:1063: var AstCopier copier; 54:1064: var auto target = (new TypeSlice).create(null); 54:1065: copier.setTargetPtr((&target.modified):AstNode**).visitConcreteType(source.modified); -:1066: 54:1067: *targetPtr = target; 54:1068: } -:1069: -:1070: @override function visitTypeStaticArray(TypeStaticArray* source) -:1071: { -:1072: var AstCopier copier; 6:1073: var auto target = (new TypeStaticArray).create(null, null); 6:1074: copier.setTargetPtr((&target.modified):AstNode**).visitConcreteType(source.modified); 6:1075: copier.setTargetPtr((&target.lengthExp):AstNode**).visitExpression(source.lengthExp); -:1076: 6:1077: *targetPtr = target; 6:1078: } -:1079: -:1080: @override function visitTypeTuple(TypeTuple* source) -:1081: { -:1082: var AstCopier copier; 2:1083: var auto target = (new TypeTuple).create([]); 2:1084: target.types.length = source.types.length; 2:1085: foreach (const auto i; var auto t) in source.types do 13:1086: copier.setTargetPtr((&target.types.ptr[i]):AstNode**).visitConcreteType(t); 2:1087: *targetPtr = target; 2:1088: } -:1089: -:1090: @override function visitTypeU16(TypeU16* source) -:1091: { 1:1092: *targetPtr = source; 1:1093: } -:1094: -:1095: @override function visitTypeU32(TypeU32* source) -:1096: { 6:1097: *targetPtr = source; 6:1098: } -:1099: -:1100: @override function visitTypeU64(TypeU64* source) -:1101: { 37:1102: *targetPtr = source; 37:1103: } -:1104: -:1105: @override function visitTypeU8(TypeU8* source) -:1106: { 92:1107: *targetPtr = source; 92:1108: } -:1109: -:1110: @override function visitTypeUnambiguous(TypeUnambiguous* source) -:1111: { -:1112: var AstCopier copier; 1:1113: var auto target = (new TypeUnambiguous).create(null); 1:1114: copier.setTargetPtr((&target.unambiguous):AstNode**).visitConcreteType(source.unambiguous); 1:1115: *targetPtr = target; 1:1116: } -:1117: -:1118: @override function visitTypeVoid(TypeVoid* source) -:1119: { 97:1120: *targetPtr = source; 97:1121: } -:1122: -:1123: @override function visitUnionDeclaration(UnionDeclaration* source) -:1124: { 2:1125: if !source do return; -:1126: 2:1127: var auto target = (new UnionDeclaration).create(source.startPos); 2:1128: entryTarget ?= target; -:1129: 2:1130: copyCommonDeclFields(source, target); 2:1131: copyCommonAggrFields(source, target); -:1132: 2:1133: if targetPtr do *targetPtr = target; 2:1134: } -:1135: -:1136: @override function visitVariableDeclaration(VariableDeclaration* source) -:1137: { 418:1138: if !source do return; -:1139: -:1140: var AstCopier copier; 418:1141: var auto target = (new VariableDeclaration).create(source.startPos, source.name); -:1142: 418:1143: copyCommonDeclFields(source, target); 418:1144: copier.setTargetPtr((&target.type):AstNode**).visitConcreteType(source.type); 418:1145: if source.initializer do 134:1146: copier.setTargetPtr((&target.initializer):AstNode**).visitExpression(source.initializer); 418:1147: target.context = source.context; -:1148: 418:1149: *targetPtr = target; 418:1150: } -:1151: -:1152: @override function visitVersionBlockDeclaration(VersionBlockDeclaration* source) -:1153: { -:1154: var AstCopier copier; 2:1155: var auto target = (new VersionBlockDeclaration).create(source.startPos); 2:1156: copyCommonDeclFields(source, target); 2:1157: const auto b = target.isTrue = source.isTrue; 2:1158: target.versionExpression = (new BoolExpression).create(source.versionExpression.startPos, null, b); 2:1159: target.versionExpression.type = TypeBool.instance(); 2:1160: if b do -:1161: { 1:1162: if source.thenDeclarations do 1:1163: copier.setTargetPtr((&target.thenDeclarations):AstNode**).visitDeclarations(source.thenDeclarations); -:1164: } 1:1165: else do if source.elseDeclarations do -:1166: { 1:1167: copier.setTargetPtr((&target.elseDeclarations):AstNode**).visitDeclarations(source.elseDeclarations); -:1168: } 2:1169: *targetPtr = target; 2:1170: } -:1171: -:1172: @override function visitVersionBlockStatement(VersionBlockStatement* source) -:1173: { -:1174: var AstCopier copier; 2:1175: var auto target = (new VersionBlockStatement).create(source.startPos); 2:1176: const auto b = target.isTrue = source.isTrue; 2:1177: target.versionExpression = (new BoolExpression).create(source.versionExpression.startPos, null, b); 2:1178: target.versionExpression.type = TypeBool.instance(); 2:1179: if b do -:1180: { 1:1181: if source.thenBlock do 1:1182: copier.setTargetPtr((&target.thenBlock):AstNode**).visitBlockStatement(source.thenBlock); -:1183: } 1:1184: else do if source.elseBlock do -:1185: { 1:1186: copier.setTargetPtr((&target.elseBlock):AstNode**).visitBlockStatement(source.elseBlock); -:1187: } 2:1188: *targetPtr = target; 2:1189: } -:1190: -:1191: @override function visitWhileStatement(WhileStatement* source) -:1192: { -:1193: var AstCopier copier; 3:1194: var auto target = (new WhileStatement).create(source.startPos); 3:1195: copier.setTargetPtr((&target.condition):AstNode**).visitExpression(source.condition); 3:1196: copier.setTargetPtr((&target.blockStatement):AstNode**).visitBlockStatement(source.blockStatement); 3:1197: *targetPtr = target; 3:1198: } -:1199: -:1200: @override function visitWithStatement(WithStatement* source) -:1201: { -:1202: var AstCopier copier; 1:1203: var auto target = (new WithStatement).create(source.startPos); 1:1204: target.expressions.length = source.expressions.length; 1:1205: foreach (const auto i; var auto e) in source.expressions do 1:1206: copier.setTargetPtr((&target.expressions.ptr[i]):AstNode**).visitExpression(e); 1:1207: copier.setTargetPtr((&target.blockStatement):AstNode**).visitBlockStatement(source.blockStatement); 1:1208: *targetPtr = target; 1:1209: } -:1210: -:1211: @override function visitXorAssignExpression(XorAssignExpression* source) -:1212: { 1:1213: var auto target = (new XorAssignExpression).create(source.startPos); 1:1214: processBinaryExp(source, target); 1:1215: *targetPtr = target; 1:1216: } -:1217: -:1218: @override function visitXorExpression(XorExpression* source) -:1219: { 1:1220: var auto target = (new XorExpression).create(source.startPos); 1:1221: processBinaryExp(source, target); 1:1222: *targetPtr = target; 1:1223: } -:1224:} <<<<<< EOF # path=src/styx/ast/declarations.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/ast/declarations.sx -: 1:unit styx.ast.declarations; -: 2: -: 3:@private import -: 4: styx.position, -: 5: styx.ast.base, -: 6: styx.ast.types, -: 7: styx.ast.visitor, -: 8: styx.scope, -: 9: styx.symbol, -: 10: styx.token, -: 11: ; -: 12: -: 13:/// Returns: A `VariableDeclaration*` if the input is one otherwise `null` -: 14:function asVariableDeclaration(Declaration* d): VariableDeclaration* -: 15:{ 8669: 16: return d.kind == $var ? *((&d):VariableDeclaration**) else null; -: 17:} -: 18: -: 19:/// Returns: A `FunctionDeclaration*` if the input is one otherwise `null` -: 20:function asFunctionDeclaration(Declaration* d): FunctionDeclaration* -: 21:{ 1973: 22: return d.kind == $function ? *((&d):FunctionDeclaration**) else null; -: 23:} -: 24: -: 25:/// Returns: A `StructDeclaration*` if the input is one otherwise `null` -: 26:function asStructDeclaration(Declaration* d): StructDeclaration* -: 27:{ 625: 28: return d.kind == $struct ? *((&d):StructDeclaration**) else null; -: 29:} -: 30: -: 31:/// Returns: An `UnionDeclaration*` if the input is one otherwise `null` -: 32:function asUnionDeclaration(Declaration* d): UnionDeclaration* -: 33:{ 625: 34: return d.kind == $union ? *((&d):UnionDeclaration**) else null; -: 35:} -: 36: -: 37:/** -: 38: * Creates a variable. -: 39: * -: 40: * At the local scope, it is automatically added to FuncDecl.allocas -: 41: * The result does not require to be symbolized. -: 42: * -: 43: * Params: -: 44: * name = The variable name -: 45: * type = the variable type -: 46: * scope_ = the scope in which the variable is put -: 47: * Returns: -: 48: * The new variable declaration. -: 49: */ -: 50:function createVariable(var Position startPos; Token* name; Type* type; -: 51: Scope* scope; bool managed): VariableDeclaration* -: 52:{ -: 53: // this can happen if the var is created for a parameter default value 3418: 54: const bool isGlobal = scope.tempOwner == null; -: 55: 3418: 56: var VariableDeclaration* result = (new VariableDeclaration).create(startPos, name, type); 3418: 57: var Symbol* owner = isGlobal ? scope.sym else scope.tempOwner; 3418: 58: result.stc += StorageClass.$var; 3418: 59: result.symbol = (new Symbol).create(name, owner, SymbolKind.variable); 3418: 60: result.symbol.astNode = result; 3418: 61: result.scope = scope; -: 62: 3418: 63: if !isGlobal do -: 64: { 3368: 65: scope.func.allocas ~= result; 3368: 66: result.flags += VariableFlag.isTemp; -: 67: } 3418: 68: if !managed do 2241: 69: result.flags += VariableFlag.skipManagment; -: 70: -: 71: //printf("added temp var %s in scope starting line %d column %d\n", name.text().ptr, scope.tempOwner.astNode.startPos.line, scope.tempOwner.astNode.startPos.column); -: 72: 3418: 73: return result; -: 74:} -: 75: -: 76:class AggregateDeclaration : Declaration -: 77:{ -: 78: /// if at least one of the member func is @operator -: 79: @@Semantic var bool hasOpOvers; -: 80: /// if .sizeof is ready -: 81: @@Semantic var bool sizeKnown; -: 82: /// Body ending position. -: 83: var Position stopPos; -: 84: /// The inheritance list. -: 85: var Type*[+] inheritanceList; -: 86: /// The declarations. -: 87: var Declarations* body; -: 88: /// The paramter-less ctor -: 89: @@Semantic var FunctionDeclaration* defaultCtor; -: 90: /// The paramter-less dtor -: 91: @@Semantic var FunctionDeclaration* defaultDtor; -: 92: /// The return value constructor -: 93: @@Semantic var FunctionDeclaration* returnCtor; -: 94: /// If it's a class, its virtual table -: 95: @@Semantic var FunctionDeclaration*[+] vtable; -: 96: /// If it's a class, the variable that carry the vtable type. -: 97: /// Note that it is not "symbolized" -: 98: @@Semantic var VariableDeclaration* vtableVar; -: 99: /// count of non static fields -:100: @@Semantic var s32 numMembers; -:101: /// if has a @operator(id) function -:102: @@Semantic var bool canResolveIdentifiers; -:103: /// 0:104: @constructor function create(){} -:105: /// -:106: @override function free() -:107: { 49:108: foreach var auto i in inheritanceList do 11:109: i.free(); 49:110: inheritanceList.decref; 49:111: body?.free(); 49:112: vtable.decref; 49:113: vtableVar?.free(); 49:114: super(); 49:115: } -:116: /// -:117: @override function accept(AstVisitor* visitor) -:118: { 6611:119: if attributes do visitor.visitAttributes(attributes); 5600:120: foreach var Type* t in inheritanceList do 1865:121: visitor.visitType(t); 6226:122: if genericParameters do visitor.visitGenericParameters(genericParameters); 11157:123: if body do visitor.visitDeclarations(body); 5600:124: } -:125:} -:126: -:127:/// AliasDeclaration -:128:@final class AliasDeclaration : Declaration -:129:{ -:130: /// If not null, either an ApplyExp, a TypeExp wrapping a function type, or a LambdaExp -:131: var Expression* exp; -:132: /// The type or the symbol when not yet solved. -:133: var Type* type; -:134: /// The source symbol once solved and if the source was not a Type. -:135: @@Semantic var Symbol* sourceSymbol; -:136: /// -:137: @constructor function create(var Position startPos; Token* name = null) -:138: { 390:139: this.kind = $alias; 390:140: this.startPos = startPos; 390:141: this.name = name; 390:142: } -:143: /// -:144: @override function free() -:145: { 26:146: type?.free(); 26:147: exp?.free(); 26:148: super(); 26:149: } -:150: /// -:151: @override function accept(AstVisitor* visitor) -:152: { 405:153: if attributes do visitor.visitAttributes(attributes); 640:154: if type do visitor.visitType(type); 545:155: if exp do visitor.visitExpression(exp); 393:156: } -:157:} -:158: -:159:/// ClassDeclaration -:160:@final class ClassDeclaration : AggregateDeclaration -:161:{ -:162: /// -:163: @constructor function create(var Position startPos) -:164: { 517:165: this.kind = $class; 517:166: this.startPos = startPos; 517:167: } -:168:} -:169: -:170:enum EnumFlag : u8 -:171:{ -:172: isEponymous, /// declared using the `#define` style -:173: isOrdered, /// member value equals previous member value plus one -:174: hasRoomForSet, /// less or same count of member as the storage bitwidth -:175: inValueRange, /// max value << rank <= storage.max -:176:} -:177: -:178:alias EnumFlags = bool[EnumFlag]; -:179: -:180:/// EnumDeclaration -:181:@final class EnumDeclaration : Declaration -:182:{ -:183: /// -:184: var EnumFlags flags; -:185: /// The enum type -:186: var Type* type; -:187: /// a TypeEnum, filled from type -:188: @@Semantic var Type* base; -:189: /// The enum members. -:190: var EnumMember*[+] members; -:191: /// -:192: @@Semantic var Expression* min; -:193: /// -:194: @@Semantic var Expression* max; -:195: /// -:196: @constructor function create(var Position startPos) -:197: { 460:198: this.kind = $enum; 460:199: this.startPos = startPos; 460:200: } -:201: /// -:202: @override function free() -:203: { 20:204: type?.free(); 20:205: foreach var auto m in members do 13:206: m.free(); 20:207: members.decref; 20:208: super(); 20:209: } -:210: /// -:211: @override function accept(AstVisitor* visitor) -:212: { 1238:213: if attributes do visitor.visitAttributes(attributes); 2252:214: if type do visitor.visitType(type); 1230:215: foreach var auto m in members do 2894:216: visitor.visitEnumMember(m); 1230:217: } -:218:} -:219: -:220:/// EnumMember -:221:@final class EnumMember : Declaration -:222:{ -:223: /// The member value. -:224: var Expression* value; -:225: /// -:226: @constructor function create(var Position startPos; Token* name; Expression* value = null) -:227: { 1025:228: this.kind = dkEnumMembr; 1025:229: this.startPos = startPos; 1025:230: this.name = name; 1025:231: this.value = value; 1025:232: } -:233: /// -:234: @override function free() -:235: { 15:236: value?.free(); 15:237: super(); 15:238: } -:239: /// -:240: @override function accept(AstVisitor* visitor) -:241: { 5153:242: if value do visitor.visitExpression(value); 2894:243: } -:244:} -:245: -:246:/// ExpressionAlias -:247:@final class ExpressionAlias : Declaration -:248:{ -:249: /// -:250: var Expression* expression; -:251: /// -:252: @constructor function create(var Position startPos; Token* name; Expression* expression) -:253: { 20:254: this.kind = eopLambda; 20:255: this.startPos = startPos; 20:256: this.name = name; 20:257: this.expression = expression; 20:258: } -:259: /// -:260: @override function accept(AstVisitor* visitor) -:261: { 132:262: if expression do visitor.visitExpression(expression); 66:263: } -:264: /// -:265: @override function free() -:266: { 2:267: expression?.free(); 2:268: super(); 2:269: } -:270:} -:271: -:272:/// Function flag -:273:enum FunctionFlag : u16 -:274:{ -:275: isUnittest, -:276: isInlineYes, -:277: isInlineMaybe, -:278: isCtor, -:279: isDtor, -:280: isVirtual, -:281: isNested, -:282: isType, -:283: isAbstract, -:284: isFinal, -:285: isStaticCtor, -:286: isStaticDtor, -:287: isCeeVariadic, -:288: isLLVM, -:289: isAsmIntel, -:290: isReadingEscapes, -:291:} -:292: -:293:/// Set of function flags -:294:alias FunctionFlags = bool[FunctionFlag]; -:295: -:296:@final class FunctionDeclaration : Declaration -:297:{ -:298: /// -:299: @@Semantic var VariableDeclaration*[+] allocas; -:300: /// Body ending position. -:301: var Position stopPos; -:302: /// The function parameters. -:303: var VariableDeclaration*[+] parameters; -:304: /// The function return. -:305: var Type* returnType; -:306: /// The body. -:307: var Statement* body; -:308: /// The asm body -:309: var Expression* asmBody; -:310: /// -:311: var Token* externalAggregate; -:312: /// Function flags -:313: @@Semantic var FunctionFlags flags; -:314: /// virtual index -:315: @@Semantic var s32 virtualIndex = -1; -:316: /// -:317: @@Semantic var VariableDeclaration*[+] escapes; -:318: /// if body sema has already been run -:319: @@Semantic var bool bodyDone; -:320: /// if the body was irgen'd once during the session -:321: @@Semantic var bool irgened; -:322: /// -:323: @constructor function create(Position startPos) -:324: { 6484:325: this.kind = $function; 6484:326: this.startPos = startPos; 6484:327: } -:328: /// -:329: @override function free() -:330: { 609:331: foreach var auto p in parameters do 169:332: p.free(); 609:333: parameters.decref; 609:334: allocas.decref; 609:335: returnType?.free(); 609:336: body?.free(); 609:337: asmBody?.free(); 609:338: escapes.decref; 609:339: super(); 609:340: } -:341: /// -:342: @override function accept(AstVisitor* visitor) -:343: { 8208:344: if attributes do visitor.visitAttributes(attributes); 5662:345: foreach var VariableDeclaration* vd in parameters do 7917:346: visitor.visitDeclaration(vd); 11324:347: if returnType do visitor.visitType(returnType); 5922:348: if genericParameters do visitor.visitGenericParameters(genericParameters); 5662:349: if body do 4963:350: visitor.visitStatement(body); 699:351: else do if asmBody do 8:352: visitor.visitExpression(asmBody); 5662:353: } -:354:} -:355: -:356:/// ImportDeclaration -:357:@final class ImportDeclaration : Declaration -:358:{ -:359: var bool isSelective; -:360: /// A list of fully qualified units. -:361: var TypeIdentifier*[+] importList; -:362: /// -:363: @constructor function create(var Position startPos) -:364: { 234:365: this.kind = $import; 234:366: this.startPos = startPos; 234:367: } -:368: /// -:369: @override function free() -:370: { 31:371: foreach var auto i in importList do 51:372: i.free(); 31:373: importList.decref; 31:374: super(); 31:375: } -:376: /// -:377: @override function accept(AstVisitor* visitor) -:378: { 442:379: if attributes do visitor.visitAttributes(attributes); 380:380: foreach var auto t in importList do 862:381: visitor.visitType(t); 380:382: } -:383:} -:384: -:385:/// LabelDeclaration -:386:@final class LabelDeclaration : Declaration -:387:{ -:388: /// indicates if the label introduces a block or if it only indicates the blocks of a loop. -:389: @@Semantic var bool hasGoto; -:390: /// -:391: @constructor function create(var Position startPos) -:392: { 20:393: this.kind = $label; 20:394: this.startPos = startPos; 20:395: } -:396: /// 49:397: @override function accept(AstVisitor* visitor) {} -:398:} -:399: -:400:/// OverloadDeclaration -:401:@final class OverloadDeclaration : Declaration -:402:{ -:403: /// The base OverloadDeclaration -:404: var Type* base; -:405: /// IdentExp or DotExp giving the members -:406: var Expression*[+] members; -:407: /// -:408: @constructor function create(var Position startPos; Token* name = null) -:409: { 64:410: this.kind = $overload; 64:411: this.startPos = startPos; 64:412: this.name = name; 64:413: } -:414: /// -:415: @override function free() -:416: { 13:417: foreach var auto m in members do 14:418: m.free(); 13:419: members.decref; 13:420: base?.free(); 13:421: super(); 13:422: } -:423: /// -:424: @override function accept(AstVisitor* visitor) -:425: { 81:426: if attributes do visitor.visitAttributes(attributes); 68:427: if base do visitor.visitType(base); 64:428: foreach var auto m in members do 152:429: visitor.visitExpression(m); 64:430: } -:431:} -:432: -:433:/// ProtectionDeclaration -:434:@final class ProtectionDeclaration : Declaration -:435:{ -:436: /// The token that specifies the new protection. -:437: var Token* $protection; -:438: /// -:439: @constructor function create(var Position startPos; Token* $protection = null) -:440: { 180:441: this.kind = TokenType.$protection; 180:442: this.startPos = startPos; 180:443: this.$protection=$protection; 180:444: } -:445: /// 1826:446: @override function accept(AstVisitor* visitor) {} -:447:} -:448: -:449:/// StaticAssertDeclaration -:450:@final class StaticAssertDeclaration: Declaration -:451:{ -:452: /// -:453: var Statement* assertion; -:454: /// -:455: @constructor function create(var Position startPos; Statement* assertion = null) -:456: { 320:457: this.kind = $assert; 320:458: this.startPos = startPos; 320:459: this.assertion = assertion; 320:460: } -:461: /// -:462: @override function free() -:463: { 57:464: assertion?.free(); 57:465: super(); 57:466: } -:467: /// -:468: @override function accept(AstVisitor* visitor) -:469: { 1556:470: if assertion do visitor.visitStatement(assertion); 778:471: } -:472:} -:473: -:474:/// StructDeclaration -:475:@final class StructDeclaration : AggregateDeclaration -:476:{ -:477: /// -:478: @constructor function create(var Position startPos) -:479: { 554:480: this.kind = $struct; 554:481: this.startPos = startPos; 554:482: } -:483:} -:484: -:485:/// UnionDeclaration -:486:@final class UnionDeclaration : AggregateDeclaration -:487:{ -:488: /// -:489: @constructor function create(var Position startPos) -:490: { 37:491: this.kind = $union; 37:492: this.startPos = startPos; 37:493: } -:494:} -:495: -:496:/// UnitDeclaration -:497:@final class UnitDeclaration : Declaration -:498:{ -:499: /// -:500: var VariableDeclaration* coverData; -:501: /// The chain of tokens used in the UnitDeclaration. -:502: var TypeIdentifier* identifiers; -:503: /// The declarations located in the unit. -:504: var Declarations* declarations; -:505: /// For error messages, copied to all the nested scopes -:506: var s8[] filename; -:507: /// -:508: var Position stopPos; -:509: /// -:510: @constructor function create(var Position startPos; Attributes* attributes; s8[] filename) -:511: { 1195:512: this.kind = $unit; 1195:513: this.startPos = startPos; 1195:514: this.attributes = attributes; 1195:515: this.filename = filename; 1195:516: } -:517: /// -:518: @override function free() -:519: { 684:520: identifiers?.free(); 684:521: declarations?.free(); 684:522: coverData?.free(); 684:523: super(); 684:524: } -:525: /// -:526: @override function accept(AstVisitor* visitor) -:527: { 2575:528: if attributes do visitor.visitAttributes(attributes); 5150:529: if declarations do visitor.visitDeclarations(declarations); 2575:530: } -:531:} -:532: -:533:/// VariableDeclaration -:534:@final class VariableDeclaration : Declaration -:535:{ -:536: /// Other infos about the variable -:537: @@Semantic var VariableFlags flags; -:538: /// Indicates the declaration context. -:539: @@Semantic var VariableDeclarationContext context; -:540: /// index for locals and non-static members -:541: @@Semantic var s32 index; -:542: /// The type of the variable. -:543: var Type* type; -:544: /// The expression that gives trhe initial value. -:545: var Expression* initializer; -:546: /// Indicates the offset, in bits, in parent Symbol -:547: @@Semantic var u32 offset; -:548: /// If != -1, gives the index of the variable to read in the struct representing the escapes -:549: @@Semantic var s32 escapeIndex = -1; -:550: /// number of times it's used as escape -:551: @@Semantic var u32 escapeUsed; -:552: /// -:553: @constructor function create(var Position startPos; Token* name = null; Type* type = null) -:554: { 21208:555: this.kind = $var; 21208:556: this.startPos = startPos; 21208:557: this.name = name; 21208:558: this.type = type; 21208:559: } -:560: /// -:561: @override function free() -:562: { 764:563: type?.free(); 764:564: initializer?.free(); 764:565: super(); 764:566: } -:567: /// -:568: @override function accept(AstVisitor* visitor) -:569: { 24398:570: if attributes do visitor.visitAttributes(attributes); 47894:571: if type do visitor.visitType(type); 32248:572: if initializer do visitor.visitExpression(initializer); 23947:573: } -:574: /// -:575: alias isParameter => context == VariableDeclarationContext.parameter; -:576: /// Returns: if the variable is a non-static class member -:577: function isClassMember(): bool 48993:578: { return symbol.parent.kind == $class && !isStatic(); } -:579: /// Returns: if the variable is a non-static struct member -:580: function isStructMember(): bool 39943:581: { return symbol.parent.kind == $struct && !isStatic(); } -:582: /// Returns: if the variable is a non-static union member -:583: function isUnionMember(): bool 37561:584: { return symbol.parent.kind == $union && !isStatic(); } -:585:} -:586: -:587:/// Enumerates the context of a variable declaration. -:588:enum VariableDeclarationContext: u8 -:589:{ -:590: default, /// global or member or local -:591: localIf, /// ifCondition -:592: localForeach, /// foreach variable -:593: parameter, /// function parameter -:594:} -:595: -:596:/// -:597:enum VariableFlag : u8 -:598:{ -:599: skipManagment, /// local could be managed but wont, e.g to prevent double free due to the initial VLA implementation -:600: isEscape, /// variable gives access to a variable declared in a parent frame -:601: isTemp, /// generated during sema -:602: isLoopCounter, /// it is the index of a foreach -:603: isImmediate, /// it can be an immediate value -:604: implicitThis, /// the auto-generated this parameter -:605:} -:606: -:607:/// -:608:alias VariableFlags = bool[VariableFlag]; -:609: -:610:/// VersionBlockDeclaration -:611:@final class VersionBlockDeclaration: Declaration -:612:{ -:613: /// Indicates which declarations are valid. -:614: @@Semantic var bool isTrue; -:615: /// Expressions allowing to select the true or false declarations. -:616: var Expression* versionExpression; -:617: /// The declarations when the versionExpression is verified. -:618: var Declarations* thenDeclarations; -:619: /// The declarations when the versionExpression is not verified. -:620: var Declarations* elseDeclarations; -:621: /// -:622: @constructor function create(var Position startPos) -:623: { 119:624: this.kind = $version; 119:625: this.startPos = startPos; 119:626: } -:627: /// -:628: @override function free() -:629: { 33:630: versionExpression?.free(); 33:631: thenDeclarations?.free(); 33:632: elseDeclarations?.free(); 33:633: super(); 33:634: } -:635: /// -:636: @override function accept(AstVisitor* visitor) -:637: { 660:638: if versionExpression do visitor.visitExpression(versionExpression); 597:639: if thenDeclarations do visitor.visitDeclarations(thenDeclarations); 343:640: if elseDeclarations do visitor.visitDeclarations(elseDeclarations); 330:641: } -:642:} <<<<<< EOF # path=src/styx/ast/expressions.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/ast/expressions.sx -: 1:unit styx.ast.expressions; -: 2: -: 3:@private import -: 4: styx.position, -: 5: styx.ast.base, -: 6: styx.ast.declarations, -: 7: styx.ast.types, -: 8: styx.ast.visitor, -: 9: styx.symbol, -: 10: styx.token, -: 11: ; -: 12: -: 13:/// -: 14:function asArrayExp(Expression* e): ArrayExpression* -: 15:{ 69868: 16: return e.operator == eopArray ? *((&e):ArrayExpression**) else null; -: 17:} -: 18:/// -: 19:function asApplyExp(Expression* e): ApplyExpression* -: 20:{ 99: 21: return e.operator == $apply ? *((&e):ApplyExpression**) else null; -: 22:} -: 23:/// -: 24:function asAssignExp(Expression* e): AssignExpression* -: 25:{ 10087: 26: return e.operator == ass ? *((&e):AssignExpression**) else null; -: 27:} -: 28:/// -: 29:function asBoolExp(Expression* e): BoolExpression* -: 30:{ 1377: 31: return e.operator == $bool ? *((&e):BoolExpression**) else null; -: 32:} -: 33:/// -: 34:function asCallExp(Expression* e): CallExpression* -: 35:{ 7533: 36: return e.operator == leftParen ? *((&e):CallExpression**) else null; -: 37:} -: 38:/// -: 39:function asCastExp(Expression* e): CastExpression* -: 40:{ 29362: 41: return e.operator == colon ? *((&e):CastExpression**) else null; -: 42:} -: 43:/// -: 44:function asConcatExp(Expression* e): ConcatExpression* -: 45:{ 5244: 46: return e.operator == tidle ? *((&e):ConcatExpression**) else null; -: 47:} -: 48:/// -: 49:function asDeclExp(Expression* e): DeclExpression* -: 50:{ 35202: 51: return e.operator == eopDecl ? *((&e):DeclExpression**) else null; -: 52:} -: 53:/// -: 54:function asDollarExp(Expression* e): DollarExpression* -: 55:{ 2: 56: return e.operator == dollar ? *((&e):DollarExpression**) else null; -: 57:} -: 58:/// -: 59:function asDotExp(Expression* e): DotExpression* -: 60:{ 14471: 61: return e.operator == dot ? *((&e):DotExpression**) else null; -: 62:} -: 63:/// -: 64:function asEchoExp(Expression* e): EchoExpression* -: 65:{ 18: 66: return e.operator == $echo ? *((&e):EchoExpression**) else null; -: 67:} -: 68:/// -: 69:function asIdentExp(Expression* e): IdentExpression* -: 70:{ 30245: 71: return e.operator == id ? *((&e):IdentExpression**) else null; -: 72:} -: 73:/// -: 74:function asIndexExp(Expression* e): IndexExpression* -: 75:{ 10804: 76: return e.operator == eopIndex ? *((&e):IndexExpression**) else null; -: 77:} -: 78:/// -: 79:function asIntegerExp(Expression* e): IntegerExpression* -: 80:{ 76723: 81: return e.operator == intLiteral || e.operator == $bool ? *((&e):IntegerExpression**) else null; -: 82:} -: 83:/// -: 84:function asLambdaExp(Expression* e): LambdaExpression* -: 85:{ 639: 86: return e.operator == eopLambda ? *((&e):LambdaExpression**) else null; -: 87:} -: 88:/// -: 89:function asLengthExp(Expression* e): LengthExpression* -: 90:{ 13070: 91: return e.operator == eopLength ? *((&e):LengthExpression**) else null; -: 92:} -: 93:/// -: 94:function asNewExp(Expression* e): NewExpression* -: 95:{ 12749: 96: return e.operator == $new ? *((&e):NewExpression**) else null; -: 97:} -: 98:/// -: 99:function asNotExp(Expression* e): NotExpression* -: 100:{ 176: 101: return e.operator == not ? *((&e):NotExpression**) else null; -: 102:} -: 103:/// -: 104:function asNullExp(Expression* e): NullExpression* -: 105:{ 7659: 106: return e.operator == $null ? *((&e):NullExpression**) else null; -: 107:} -: 108:/// -: 109:function asOpOverloadMacro(Expression* e): OpOverloadMacro* -: 110:{ 5112: 111: return e.operator == eopOpOvMacro ? *((&e):OpOverloadMacro**) else null; -: 112:} -: 113:/// -: 114:function asOptAccessExp(Expression* e): OptAccessExpression* -: 115:{ 36827: 116: return e.operator == optAccess ? *((&e):OptAccessExpression**) else null; -: 117:} -: 118:/// -: 119:function asPtrExp(Expression* e): PtrExpression* -: 120:{ 4: 121: return e.operator == eopPtr ? *((&e):PtrExpression**) else null; -: 122:} -: 123:/// -: 124:function asRangeExp(Expression* e): RangeExpression* -: 125:{ 7079: 126: return e.operator == dotDot ? *((&e):RangeExpression**) else null; -: 127:} -: 128:/// -: 129:function asSetLengthExp(Expression* e): SetLengthExpression* -: 130:{ 2: 131: return e.operator == eopSetLength ? *((&e):SetLengthExpression**) else null; -: 132:} -: 133:/// -: 134:function asSliceExp(Expression* e): SliceExpression* -: 135:{ 21081: 136: return e.operator == eopSlice ? *((&e):SliceExpression**) else null; -: 137:} -: 138:/// -: 139:function asStringExp(Expression* e): StringExpression* -: 140:{ 21751: 141: return e.operator == stringLiteral ? *((&e):StringExpression**) else null; -: 142:} -: 143:/// -: 144:function asSuperExp(Expression* e): SuperExpression* -: 145:{ 4830: 146: return e.operator == $super ? *((&e):SuperExpression**) else null; -: 147:} -: 148:/// -: 149:function asTupleExp(Expression* e): TupleExpression* -: 150:{ 10726: 151: return e.operator == rightParen ? *((&e):TupleExpression**) else null; -: 152:} -: 153:/// -: 154:function asTypeExp(Expression* e): TypeExpression* -: 155:{ 50315: 156: return e.operator == eopType ? *((&e):TypeExpression**) else null; -: 157:} -: 158:/// Returns: If the input expression is of form `e.reverse` then `e` else `null`. -: 159:function isReverse(Expression* node): Expression* -: 160:{ 589: 161: var DotExpression* de = asDotExp(node); 589: 162: var IdentExpression* id = de ? asIdentExp(de.dotted) else null; 589: 163: return id && id.identifier.iptr() == reverseToken().iptr() ? de.expression else null; -: 164:} -: 165:/// Returns: the IdentExp for a given variable -: 166:function varToIdentExp(VariableDeclaration* node): IdentExpression* -: 167:{ 2898: 168: return (new IdentExpression).create(node.startPos, node.name, node.type, node.symbol); -: 169:} -: 170: -: 171:/// AddAssExpression -: 172:@final class AddAssignExpression : AssignExpression -: 173:{ -: 174: /// 508: 175: @override function setOperator() { operator = plusAss; } -: 176:} -: 177: -: 178:/// AddExpression -: 179:@final class AddExpression : BinaryExpression -: 180:{ -: 181: /// 2498: 182: @override function setOperator() { operator = plus; } -: 183:} -: 184: -: 185:/// AndExpression -: 186:class AndAndExpression : BinaryExpression -: 187:{ -: 188: /// 2124: 189: @override function setOperator() { operator = andAnd; } -: 190:} -: 191: -: 192:/// AndAssignExpression -: 193:@final class AndAssignExpression : AssignExpression -: 194:{ -: 195: /// 22: 196: @override function setOperator() { operator = ampAss; } -: 197:} -: 198: -: 199:/// AndExpression -: 200:@final class AndExpression : BinaryExpression -: 201:{ -: 202: /// 56: 203: @override function setOperator() { operator = amp; } -: 204:} -: 205: -: 206:@final class ApplyExpression : Expression -: 207:{ -: 208: /// If written using the postfix style -: 209: var bool postStyle; -: 210: /// postfix style w/o angle brackets -: 211: var bool noBracket; -: 212: /// The generic to process -: 213: var Expression* generic; -: 214: /// The expressions to apply -: 215: var Expression*[+] arguments; -: 216: /// gives the application -: 217: @@Semantic var IdentExpression* application; -: 218: /// -: 219: @constructor function create(var Position startPos; Expression* generic; Expression*[+] arguments; -: 220: bool postStyle = false; bool noBracket = false) -: 221: { 730: 222: this.startPos = startPos; 730: 223: this.operator = $apply; 730: 224: this.generic = generic; 730: 225: this.arguments = arguments; 730: 226: this.noBracket = noBracket; 730: 227: this.postStyle = postStyle; 730: 228: } -: 229: /// -: 230: @override function free() -: 231: { 236: 232: generic?.free(); 236: 233: foreach var auto a in arguments do 285: 234: a.free(); 236: 235: arguments.decref; 236: 236: super(); 236: 237: } -: 238: /// -: 239: @override function accept(AstVisitor* visitor) -: 240: { 1374: 241: if generic do visitor.visitExpression(generic); 687: 242: foreach var auto a in arguments do 898: 243: visitor.visitExpression(a); 687: 244: } -: 245:} -: 246: -: 247:/// ArrayExpression -: 248:@final class ArrayExpression : Expression -: 249:{ -: 250: /// Indicates if the array contains only constant elems, e.g literals -: 251: @@Semantic var bool isStaticallyEvaluable; -: 252: /// If nested -: 253: @@Semantic var ArrayExpression* parentArray; -: 254: /// the array elements -: 255: var Expression*[+] items; -: 256: /// A generated variable allowing to use the array as a lvalue -: 257: @@Semantic var Declaration* asLvalue; -: 258: /// -: 259: @constructor function create(var Position startPos) -: 260: { 429: 261: this.operator = eopArray; 429: 262: this.startPos = startPos; 429: 263: } -: 264: /// -: 265: @override function free() -: 266: { 27: 267: asLvalue?.free(); 27: 268: foreach var auto i in items do 30: 269: i.free(); 27: 270: items.decref; 27: 271: super(); 27: 272: } -: 273: /// -: 274: @override function accept(AstVisitor* visitor) -: 275: { 351: 276: foreach var auto i in items do 2354: 277: visitor.visitExpression(i); 351: 278: } -: 279: /// 163: 280: @override function canInitialize(): bool { return isStaticallyEvaluable; } -: 281: /// 19: 282: @override function isLiteral(): bool { return canInitialize(); } -: 283:} -: 284: -: 285:/// AsmExpression -: 286:@final class AsmExpression : Expression -: 287:{ -: 288: // The return type -: 289: var Type* returnType; -: 290: // code -: 291: var Token* code; -: 292: // constraints -: 293: var Token* constraint; -: 294: // argument -: 295: var Expression*[+] arguments; -: 296: /// -: 297: @constructor function create(var Position startPos) -: 298: { 30: 299: this.operator = $asm; 30: 300: this.startPos = startPos; 30: 301: } -: 302: @override function free() -: 303: { 21: 304: foreach var auto a in arguments do a.free(); 14: 305: arguments.decref; 14: 306: returnType?.free(); 14: 307: super(); 14: 308: } -: 309: /// -: 310: @override function accept(AstVisitor* visitor) -: 311: { 24: 312: foreach var auto a in arguments do visitor.visitExpression(a); 32: 313: if returnType do visitor.visitType(returnType); 16: 314: } -: 315:} -: 316: -: 317:/// AssignExpression -: 318:class AssignExpression : BinaryExpression -: 319:{ -: 320: /// 12862: 321: @override function setOperator() {operator = ass;} -: 322: /// -: 323: @override function isLvalue(): bool -: 324: { 806: 325: return left.isLvalue(); -: 326: } -: 327:} -: 328: -: 329:/// AtExpression -: 330:@final class AtExpression : UnaryExpression -: 331:{ -: 332: /// 2240: 333: @override function setOperator() { operator = eopAt; } -: 334: /// -: 335: @override function canInitialize(): bool -: 336: { 10: 337: var FunctionDeclaration* fd = symToFuncDecl(symbol); 10: 338: return fd?.isStatic(); -: 339: } -: 340:} -: 341: -: 342:/// BoolExpression -: 343:@final class BoolExpression : IntegerExpression -: 344:{ -: 345:protection (private) -: 346: -: 347: static var BoolExpression* $false; -: 348: -: 349: @destructor static function staticDtor() -: 350: { 374: 351: $false.free(); 374: 352: } -: 353: -: 354: @constructor static function staticCtor() -: 355: { 374: 356: $false = (new BoolExpression).create((0,0), null, false); 374: 357: } -: 358: -: 359:protection (public) -: 360: /// -: 361: @constructor function create(Position startPos; Token* tok = null; bool value = false; Type* type = null) -: 362: { 3353: 363: this.operator = TokenType.$bool; 3353: 364: this.startPos = startPos; 3353: 365: this.tok = tok; 3353: 366: this.value = value; 3353: 367: this.type = type; 3353: 368: } -: 369: /// Returns: The shared expression for `false`. -: 370: /// Should only be used for expressions guaranteed to be valid, e.g lowerings. 5271: 371: static function getFalse(): BoolExpression* { return $false; } -: 372:} -: 373: -: 374:/// CallExpression -: 375:@final class CallExpression : UnaryExpression -: 376:{ -: 377: /// the call is already rewritten, dont try operator over again -: 378: @@Semantic var bool isOpOverRewrite; -: 379: /// -: 380: @@Semantic var bool isDevirtualized; -: 381: /// true: lowering for `@constructor` call has already set the hidden `this` -: 382: @@Semantic var bool isThisAdded; -: 383: /// -: 384: @@Semantic var bool checkThis; -: 385: /// The arguments, always positioned, never named -: 386: var Expression*[+] arguments; -: 387: /// The function being called -: 388: var FunctionDeclaration* fd; -: 389: /// Return a value by reference -: 390: @@Semantic var bool isValueCtor; -: 391: /// 28366: 392: @override function setOperator() { operator = leftParen; } -: 393: /// -: 394: @override function free() -: 395: { 4009: 396: foreach var auto a in arguments do a.free(); 1958: 397: arguments.decref; 1958: 398: super(); 1958: 399: } -: 400: /// -: 401: @override function accept(AstVisitor* visitor) -: 402: { 10906: 403: super.accept(visitor); 22967: 404: foreach var auto a in arguments do visitor.visitExpression(a); 10906: 405: } -: 406: /// -: 407: @override function isLvalue(): bool -: 408: { 6653: 409: return isValueCtor || fd && fd.isVar(); -: 410: } -: 411:} -: 412: -: 413:/// Enumerates the possible kind of cast covered by CastExpression -: 414:enum CastKind : u8 -: 415:{ -: 416: invalid, /// state before semantic pass or never allowed -: 417: -: 418: same, /// same type -: 419: -: 420: intExt, /// to wider integer type (implicit) -: 421: fpExt, /// to wider floating point type (implicit) -: 422: intToFp, /// convert integer to floating point (implicit) -: 423: staticCastP,/// cast from a class ptr type to base (implicit) -: 424: staticCastS,/// cast from a class value type to base (implicit) -: 425: nullCast, /// null to reference type (implicit) -: 426: staToPtr, /// static array to pointer to elem type (implicit) -: 427: intToEnum, /// intliteral to enum base type (implicit) -: 428: intToSet, /// int to EnumSet -: 429: strToChar, /// from string literal of length 1 to s8 (implicit) -: 430: strToDyna, /// from string literal to dynamic array (implicit) -: 431: staToDyna, /// from static array to dynamic array (implicit) -: 432: staElems, /// from array literal to other static array (implicit) -: 433: staToESet, /// from array literal to enum set (implicit) -: 434: strToRca, /// from string literal to ref counted array -: 435: staToRca, /// from static array to ref counted array (implicit) -: 436: strToSta, /// from string literal to static array (implicit) -: 437: rcaToDyna, /// from counted array to dynamic array (implicit) -: 438: dynaToRca, /// from dynamic array to ref counted array (implicit) -: 439: opTrue, /// from agg to bool, using @operator(true) (implicit) -: 440: funRet, /// function pointer return type inherits of expected function pointer return type -: 441: tupToElem, /// tuple made of single element to element -: 442: elemToTup, /// element to tuple of element -: 443: tupToStruct,/// tuple to struct -: 444: -: 445: intTrunc, /// to smaller integer type (explicit) -: 446: fpTrunc, /// to smaller floating point type (explicit) -: 447: fpToInt, /// make integer using integral part (explicit) -: 448: bitCast, /// reinterpret (explicit) -: 449: ptrCast, /// reinterpret pointer (explicit) -: 450: dynCastP, /// from a class ptr type to another (explicit) -: 451: dynCastS, /// from a class value type to another (explicit) -: 452: intToPtr, /// from an int to a pointer (explicit) -: 453: toCond, /// to condition -: 454: voidCast, /// discard side effect -: 455:} -: 456: -: 457:/// CastExpression -: 458:@final class CastExpression : UnaryExpression -: 459:{ -: 460: /// -: 461: @@Semantic var CastKind kind; -: 462: /// -: 463: var Type* toType; -: 464: /// -: 465: @override function setOperator() { assert(0); } -: 466: /// -: 467: @constructor function create(var Position startPos; Expression* expression = null; -: 468: Type* toType = null; CastKind kind = CastKind.invalid; bool setType = false) -: 469: { 13251: 470: this.operator = colon; 13251: 471: this.startPos = startPos; 13251: 472: this.expression = expression; 13251: 473: this.toType = toType; 13251: 474: this.kind = kind; 22761: 475: if setType do type = toType; 13251: 476: } -: 477: /// -: 478: @override function free() -: 479: { 19: 480: toType?.free(); 19: 481: super(); 19: 482: } -: 483: /// -: 484: @override function accept(AstVisitor* visitor) -: 485: { 3568: 486: super(visitor); 7136: 487: if toType do visitor.visitType(toType); 3568: 488: } -: 489: /// 33: 490: @override function canInitialize(): bool { return expression.canInitialize(); } -: 491: /// 56: 492: @override function isLiteral(): bool { return expression.isLiteral(); } -: 493:} -: 494: -: 495:/// CmpExpression -: 496:@final class CmpExpression : BinaryExpression -: 497:{ -: 498: /// if comparing using != and == on value type or arrays -: 499: @@Semantic var ExtendedTokenType buitlinCmpType; -: 500: /// -: 501: @constructor function create(var Position startPos; TokenType operator; Expression* left = null; Expression* right = null; Type* type = null) -: 502: { 8229: 503: super(startPos, left, right, type); -: 504: // after the call to setOperator 8229: 505: this.operator = operator; 8229: 506: } -: 507: /// 16458: 508: @override function setOperator() { operator = TokenType.equal; } -: 509:} -: 510: -: 511:/// Describes the different ways the a ConcatAssignExpression work at runtime -: 512:enum ConcatKind -: 513:{ -: 514: slice, // call rtl_rcaAppend() with `rhs.ptr and `rhs.length` -: 515: lvalue, // call rtl_rcaAppend() with `&rhs` and `1` -: 516: rvalue, // call several rtl funcs to do `lhs.length += 1, *(lhs.ptr + oldLen) = rhs` -: 517:} -: 518: -: 519:/// ConcatAssignExpression -: 520:@final class ConcatAssignExpression : AssignExpression -: 521:{ -: 522: /// -: 523: @@Semantic var ConcatKind kind; -: 524: /// -: 525: @@Semantic var VariableDeclaration* asLvalue; -: 526: /// 1744: 527: @override function setOperator() {operator = tidAss;} -: 528:} -: 529: -: 530:/// AndExpression -: 531:@final class ConcatExpression : BinaryExpression -: 532:{ -: 533: /// Defines if a chunk is copied or a single value appended -: 534: @@Semantic var bool isLeftMemCpy; -: 535: /// Defines if a chunk is copied or a single value appended -: 536: @@Semantic var bool isRightMemCpy; -: 537: /// The result of the concatenation, wouth the side-effect -: 538: @@Semantic var IdentExpression* result; -: 539: /// Used to set `result` .length -: 540: var SetLengthExpression* setLength; -: 541: /// Gives `result.ptr` -: 542: var Expression* destPtr; -: 543: /// `left.ptr` when left is an array -: 544: var Expression* leftPtr; -: 545: /// `1` or `left.length` -: 546: var Expression* leftLength; -: 547: /// `right.ptr` when left is an array -: 548: var Expression* rightPtr; -: 549: /// `1` or `right.length` -: 550: var Expression* rightLength; -: 551: /// 190: 552: @override function setOperator() { operator = tidle; } -: 553: /// -: 554: @override function free() -: 555: { 3: 556: super(); 3: 557: } -: 558: /// as `result` is a lvalue 35: 559: @override function isLvalue(): bool { return true; } -: 560:} -: 561: -: 562:/// ConditionalExpression -: 563:@final class ConditionalExpression : Expression -: 564:{ -: 565: /// Indicates if the condition gives the actual thenExpression -: 566: var bool isShorthandSyntax; -: 567: /// -: 568: var Expression* condition; -: 569: /// -: 570: var Expression* thenExpression; -: 571: /// -: 572: var Expression* elseExpression; -: 573: /// -: 574: @constructor function create(var Position startPos; Expression* condition = null; -: 575: Expression* thenExpression = null; Expression* elseExpression = null) -: 576: { 615: 577: this.operator = TokenType.qmark; 615: 578: this.startPos = startPos; 615: 579: this.condition = condition; 615: 580: this.thenExpression = thenExpression; 615: 581: this.elseExpression = elseExpression; 615: 582: } -: 583: /// -: 584: @override function free() -: 585: { 44: 586: condition?.free(); 88: 587: if !isShorthandSyntax do thenExpression?.free(); 44: 588: elseExpression?.free(); 44: 589: super(); 44: 590: } -: 591: /// -: 592: @override function accept(AstVisitor* visitor) -: 593: { 1268: 594: if condition do visitor.visitExpression(condition); 1268: 595: if thenExpression do visitor.visitExpression(thenExpression); 1227: 596: if elseExpression do visitor.visitExpression(elseExpression); 634: 597: } -: 598: /// -: 599: @override function isLvalue(): bool -: 600: { 1555: 601: return thenExpression.isLvalue() && elseExpression.isLvalue(); -: 602: } -: 603:} -: 604: -: 605:/// DeclExpression -: 606:@final class DeclExpression : Expression -: 607:{ -: 608: /// the declaration -: 609: var Declaration* declaration; -: 610: /// if there is something to do right after decl. -: 611: var Expression* expression; -: 612: /// -: 613: @constructor function create(var Position startPos; Declaration* declaration = null; -: 614: Expression* expression = null; Type* type = null; Symbol* symbol = null) -: 615: { 906: 616: this.operator = eopDecl; 906: 617: this.startPos = startPos; 906: 618: this.declaration = declaration; 906: 619: this.expression = expression; 906: 620: this.type = type; 906: 621: this.symbol = symbol; 906: 622: } -: 623: /// -: 624: @override function free() -: 625: { 0: 626: declaration?.free(); 0: 627: expression?.free(); 0: 628: super(); 0: 629: } -: 630: /// -: 631: @override function accept(AstVisitor* visitor) -: 632: { 14: 633: if declaration do visitor.visitDeclaration(declaration); 12: 634: if expression do visitor.visitExpression(expression); 7: 635: } -: 636: /// -: 637: @override function isLvalue(): bool -: 638: { 440: 639: return expression ? expression.isLvalue() else declaration.kind == $var; -: 640: } -: 641:} -: 642: -: 643:/// DeleteExpression -: 644:@final class DeleteExpression : Expression -: 645:{ -: 646: /// Gives the thing to deallocate -: 647: var Expression* expression; -: 648: /// Gives a `function(u8* ptr)`, e.g `free` -: 649: var Expression* deallocator; -: 650: /// The destructor is expression gives a pointer to a TypeAggregate -: 651: @@Semantic var FunctionDeclaration* dtor; -: 652: /// -: 653: @constructor function create(var Position startPos; Expression* expression = null; Expression* deallocator = null) -: 654: { 258: 655: this.operator = TokenType.$delete; 258: 656: this.startPos = startPos; 258: 657: this.expression = expression; 258: 658: this.deallocator= deallocator; 258: 659: } -: 660: /// -: 661: @override function free() -: 662: { 12: 663: expression?.free(); 12: 664: deallocator?.free(); 12: 665: super(); 12: 666: } -: 667: /// -: 668: @override function accept(AstVisitor* visitor) -: 669: { 278: 670: if expression do visitor.visitExpression(expression); 144: 671: if deallocator do visitor.visitExpression(deallocator); 139: 672: } -: 673:} -: 674: -: 675:/// DerefExpression -: 676:@final class DerefExpression : UnaryExpression -: 677:{ -: 678: /// 2782: 679: @override function setOperator() { operator = eopDeref; } -: 680: /// 1233: 681: @override function isLvalue(): bool { return true; } -: 682:} -: 683: -: 684:/// DivAssignExpression -: 685:@final class DivAssignExpression : AssignExpression -: 686:{ -: 687: /// 108: 688: @override function setOperator() { operator = divAss; } -: 689:} -: 690: -: 691:/// DivExpression -: 692:@final class DivExpression : BinaryExpression -: 693:{ -: 694: /// 586: 695: @override function setOperator() { operator = div; } -: 696:} -: 697: -: 698:/// DollarExpression -: 699:@final class DollarExpression : UnaryExpression -: 700:{ 246: 701: @override function setOperator() { operator = TokenType.dollar; } -: 702:} -: 703: -: 704:/// DotExpression -: 705:@final class DotExpression : UnaryExpression -: 706:{ -: 707: var bool checkDotVar; -: 708: /// -: 709: var Expression* dotted; -: 710: /// -: 711: @constructor function create(var Position startPos; Expression* expression; -: 712: Expression* dotted; Type* type = null; Symbol* symbol = null) -: 713: { 18961: 714: this.operator = TokenType.dot; 18961: 715: this.startPos = startPos; 18961: 716: this.expression = expression; 18961: 717: this.dotted = dotted; 18961: 718: this.type = type; 18961: 719: this.symbol = symbol; 18961: 720: } -: 721: /// -: 722: @override function free() -: 723: { 1336: 724: dotted?.free(); 1336: 725: super(); 1336: 726: } -: 727: /// -: 728: @override function setOperator() { assert(0); } -: 729: /// -: 730: @override function accept(AstVisitor* visitor) -: 731: { 16687: 732: super.accept(visitor); 33374: 733: if dotted do visitor.visitExpression(dotted); 16687: 734: } -: 735: /// 7931: 736: @override function isLvalue(): bool { return dotted.isLvalue(); } -: 737: /// 2300: 738: @override function isAssignable(): bool {return dotted.isAssignable(); } -: 739: /// 18: 740: @override function canInitialize(): bool {return dotted.canInitialize(); } -: 741: /// -: 742: @override function isEqual(Object* other): bool -: 743: { 14: 744: if var auto that = other:DotExpression* do 7: 745: return that.expression == expression && that.dotted == dotted; 0: 746: return false; -: 747: } -: 748:} -: 749: -: 750:/// EchoExpression -: 751:@final class EchoExpression : Expression -: 752:{ -: 753: /// The command that indicates the thing to echo -: 754: var Token* command; -: 755: /// The command arguments. -: 756: var Expression*[+] arguments; -: 757: /// -: 758: @constructor function create(var Position startPos; Token* command = null) -: 759: { 1156: 760: this.operator = $echo; 1156: 761: this.startPos = startPos; 1156: 762: this.command = command; 1156: 763: } -: 764: /// -: 765: @override function free() -: 766: { 277: 767: foreach var auto a in arguments do 16: 768: a.free(); 277: 769: arguments.decref; 277: 770: super(); 277: 771: } -: 772: /// -: 773: @override function accept(AstVisitor* visitor) -: 774: { 321: 775: foreach var auto a in arguments do 418: 776: visitor.visitExpression(a); 321: 777: } -: 778:} -: 779: -: 780:/// FloatExpression -: 781:@final class FloatExpression : Expression -: 782:{ -: 783: /// -: 784: var Token* tok; -: 785: /// -: 786: var f64 value; -: 787: /// -: 788: @constructor function create(var Position startPos; Token* tok = null; f64 value = 0; Type* type = null) -: 789: { 159: 790: this.operator = floatLiteral; 159: 791: this.startPos = startPos; 159: 792: this.value = value; 159: 793: this.type = type; 159: 794: this.tok = tok; 159: 795: } -: 796: /// 125: 797: @override function accept(AstVisitor* visitor){} -: 798: /// 19: 799: @override function canInitialize(): bool { return true; } -: 800: /// 17: 801: @override function isLiteral(): bool { return true; } -: 802: /// -: 803: @override function isEqual(Object* other): bool -: 804: { -: 805: assert(0); -: 806: } -: 807:} -: 808: -: 809:/// IdentExpression -: 810:class IdentExpression : Expression -: 811:{ -: 812: /// the identifier -: 813: var Token* identifier; -: 814: /// -: 815: @constructor function create(var Position startPos; Token* identifier; Type* type = null; Symbol* symbol = null) -: 816: { 77571: 817: this.operator = TokenType.id; 77571: 818: this.startPos = startPos; 77571: 819: this.identifier = identifier; 77571: 820: this.type = type; 77571: 821: this.symbol = symbol; 77571: 822: } -: 823: /// 64536: 824: @override function accept(AstVisitor* visitor) {} -: 825: /// -: 826: @override function isLvalue(): bool -: 827: { 52036: 828: var auto vd = symToVarDecl(symbol); 52036: 829: return vd && isImmediate !in vd.flags; -: 830: } -: 831: /// -: 832: @override function isAssignable(): bool -: 833: { 12902: 834: if var auto vd = symToVarDecl(symbol) do 6440: 835: return !vd.isConst(); 11: 836: return isLvalue(); -: 837: } -: 838: /// -: 839: @override function canInitialize(): bool -: 840: { 202: 841: if var auto em = symToEnumMember(symbol) do 6: 842: return true; 95: 843: return false; -: 844: } -: 845: /// -: 846: @override function isEqual(Object* other): bool -: 847: { 42: 848: if var auto that = other:IdentExpression* do 19: 849: return that.type == type && that.symbol:u8* == symbol:u8*; 2: 850: return false; -: 851: } -: 852:} -: 853: -: 854:/// MulExpression -: 855:@final class InExpression : BinaryExpression -: 856:{ -: 857: /// !in -: 858: var bool negated; -: 859: /// -: 860: @constructor function create(var Position startPos; Expression* left = null; -: 861: Expression* right = null; bool negated = false; Type* type = null; Symbol* symbol = null) -: 862: { 196: 863: super(startPos, left, right, type, symbol); 196: 864: this.negated = negated; 196: 865: } -: 866: /// 392: 867: @override function setOperator() { operator = $in; } -: 868:} -: 869: -: 870:/// IndexExpression -: 871:@final class IndexExpression : UnaryExpression -: 872:{ -: 873: /// -: 874: @@Semantic var Type* arrayType; -: 875: /// Stores the source array length for bound checks -: 876: @@Semantic var Expression* sourceLength; -: 877: /// The expression that gives the index. -: 878: var Expression*[+] indexes; -: 879: /// -: 880: @constructor function create(var Position startPos; Expression* expression; Expression* index; Type* type = null) -: 881: { 1780: 882: this.startPos = startPos; 1780: 883: this.expression = expression; 1780: 884: this.indexes ~= index; 1780: 885: this.type = type; 1780: 886: this.operator = eopIndex; 1780: 887: this.arrayType = expression?.type; 1780: 888: } -: 889: /// -: 890: @override function setOperator() { assert(0); } -: 891: /// -: 892: @override function free() -: 893: { 45: 894: foreach var auto i in indexes do i.free(); 20: 895: indexes.decref; 20: 896: super(); 20: 897: } -: 898: /// -: 899: @override function accept(AstVisitor* visitor) -: 900: { 1477: 901: super(visitor); 2961: 902: foreach var auto i in indexes do visitor.visitExpression(i); 1477: 903: } -: 904: /// -: 905: @override function isLvalue(): bool -: 906: { 2106: 907: if var auto tt = asTypeTuple(expression.type) do 97: 908: return expression.isLvalue(); 956: 909: return arrayType.kind != tkEnumSet; -: 910: } -: 911: /// -: 912: @override function isAssignable(): bool -: 913: { 536: 914: if var auto tt = asTypeTuple(expression.type) do -: 915: { 10: 916: var auto te = asTupleExp(expression); 10: 917: return te ? te.expressions[getIntLiteral(indexes[0]).value].isLvalue() 9: 918: else expression.isLvalue(); -: 919: } 258: 920: return true; -: 921: } -: 922:} -: 923: -: 924:/// IntegerExpression -: 925:class IntegerExpression : Expression -: 926:{ -: 927: /// -: 928: var Token* tok; -: 929: /// -: 930: var u64 value; -: 931: /// -: 932: @constructor function create(Position startPos; Token* tok = null; u64 value = 0; Type* type = null) -: 933: { 65206: 934: this.operator = intLiteral; 65206: 935: this.startPos = startPos; 65206: 936: this.tok = tok; 65206: 937: this.value = value; 65206: 938: this.type = type; 65206: 939: } -: 940: /// 12493: 941: @final @override function accept(AstVisitor* visitor){} -: 942: /// 672: 943: @final @override function canInitialize(): bool { return true; } -: 944: /// 45702: 945: @final @override function isLiteral(): bool { return true; } -: 946: /// -: 947: @override function isEqual(Object* other): bool -: 948: { -: 949: assert(0); -: 950: } -: 951:} -: 952: -: 953:/// LShiftAssignExpression -: 954:@final class LShiftAssignExpression : AssignExpression -: 955:{ -: 956: /// 12: 957: @override function setOperator() { operator = lshiftAss; } -: 958:} -: 959: -: 960:/// LShiftExpression -: 961:@final class LShiftExpression : BinaryExpression -: 962:{ -: 963: /// 22: 964: @override function setOperator() { operator = lShift; } -: 965:} -: 966: -: 967:/// LambdaExpression -: 968:@final class LambdaExpression : Expression -: 969:{ -: 970: /// The function, lowered to a standard function declaration -: 971: var FunctionDeclaration* func; -: 972: /// if the body consists of a single exp, this exp. -: 973: @@Semantic var Expression* bodyAsExp; -: 974: /// if sema should create a an AtExp (isGenericArg=false) or not (isGenericArg=true) -: 975: @@Semantic var bool isGenericArg; -: 976: /// -: 977: @constructor function create(var Position startPos; FunctionDeclaration* func; Expression* bodyAsExp) -: 978: { 32: 979: this.operator = eopLambda; 32: 980: this.startPos = startPos; 32: 981: this.func = func; 32: 982: this.bodyAsExp = bodyAsExp; 32: 983: } -: 984: /// -: 985: @override function free() -: 986: { 6: 987: if func do -: 988: { 6: 989: delete this.func.name; 6: 990: func.free(); -: 991: } 6: 992: super(); 6: 993: } -: 994: /// 25: 995: @override function accept(AstVisitor* visitor) { } -: 996:} -: 997: -: 998:/// LengthExpression -: 999:@final class LengthExpression : UnaryExpression -:1000:{ -:1001: @@Semantic var Type* targetType; -:1002: /// -:1003: @constructor function create(Expression* expression; bool isRewritten; Type* type = null) -:1004: { 2592:1005: this.startPos = expression.startPos; 2592:1006: this.operator = eopLength; 2592:1007: this.expression = getArrayOpResult(expression, isRewritten); 2592:1008: this.type = type; 2592:1009: this.targetType = expression.type; 2592:1010: } -:1011: /// -:1012: @override function setOperator() { assert(0); } -:1013:} -:1014: -:1015:/// ModAssignExpression -:1016:@final class ModAssignExpression : AssignExpression -:1017:{ -:1018: /// 12:1019: @override function setOperator() { operator = modAss; } -:1020:} -:1021: -:1022:/// ModExpression -:1023:@final class ModExpression : BinaryExpression -:1024:{ -:1025: /// 142:1026: @override function setOperator() { operator = mod; } -:1027:} -:1028: -:1029:/// MulAssignExpression -:1030:@final class MulAssignExpression : AssignExpression -:1031:{ -:1032: /// 30:1033: @override function setOperator() { operator = mulAss; } -:1034:} -:1035: -:1036:/// MulExpression -:1037:@final class MulExpression : BinaryExpression -:1038:{ -:1039: /// 992:1040: @override function setOperator() { operator = mul; } -:1041:} -:1042: -:1043:/// NegExpression -:1044:@final class NegExpression: UnaryExpression -:1045:{ 570:1046: @override function setOperator() { operator = ExtendedTokenType.eopNeg; } -:1047:} -:1048: -:1049:/// NewExpression -:1050:@final class NewExpression : Expression -:1051:{ -:1052: /// Gives the thing to deallocate -:1053: var Expression* expression; -:1054: /// Gives a `function(usize n): u8*`, e.g `malloc` -:1055: var Expression* allocator; -:1056: /// -:1057: @constructor function create(var Position startPos; Expression* expression = null; Expression* allocator = null) -:1058: { 997:1059: this.operator = TokenType.$new; 997:1060: this.startPos = startPos; 997:1061: this.expression = expression; 997:1062: this.allocator = allocator; 997:1063: } -:1064: /// -:1065: @override function free() -:1066: { 164:1067: expression?.free(); 164:1068: allocator?.free(); 164:1069: super(); 164:1070: } -:1071: /// -:1072: @override function accept(AstVisitor* visitor) -:1073: { 1584:1074: if expression do visitor.visitExpression(expression); 800:1075: if allocator do visitor.visitExpression(allocator); 792:1076: } -:1077:} -:1078: -:1079:/// NotExpression -:1080:@final class NotExpression: UnaryExpression -:1081:{ 2806:1082: @override function setOperator() { operator = TokenType.not; } -:1083:} -:1084: -:1085:/// NullExpression -:1086:@final class NullExpression : Expression -:1087:{ -:1088: /// -:1089: @constructor function create(var Position startPos; Type* type = null) -:1090: { 3827:1091: this.operator = $null; 3827:1092: this.startPos = startPos; 3827:1093: this.type = type; 3827:1094: } -:1095: /// 1092:1096: @override function accept(AstVisitor* visitor){} -:1097: /// 12:1098: @override function canInitialize(): bool { return true; } -:1099: /// 19:1100: @override function isLiteral(): bool { return true; } -:1101:} -:1102: -:1103:/// OneCompExpression -:1104:@final class OneCompExpression : UnaryExpression -:1105:{ 40:1106: @override function setOperator() { operator = ExtendedTokenType.eopPreTidle; } -:1107:} -:1108: -:1109:enum OpOverloadKind : u8 -:1110:{ -:1111: default, // the exp template gives exactly what it overloads -:1112: indexAssign, // `a[b] = c` -:1113: sliceAssign, // `a[] = b` or `a[b..c] = c` -:1114:} -:1115: -:1116:@final class OpOverloadMacro : UnaryExpression -:1117:{ -:1118: /// -:1119: var OpOverloadKind kind; -:1120: /// -:1121: @constructor function create(Expression* expression; OpOverloadKind kind) -:1122: { 4:1123: this.operator = eopOpOvMacro; 4:1124: this.kind = kind; 4:1125: this.expression = expression; 4:1126: this.startPos = expression.startPos; 4:1127: } -:1128: /// -:1129: @override function setOperator() { assert(0); } -:1130:} -:1131: -:1132:/// OptAccessExpression -:1133:@final class OptAccessExpression : UnaryExpression -:1134:{ -:1135: /// The type of the pseudo RHS value -:1136: @@Semantic var Type* valueType; -:1137: /// Used to provide the pseudo RHS value as a lvalue -:1138: @@Semantic var VariableDeclaration* valueVar; -:1139: /// 344:1140: @override function setOperator() { operator = TokenType.optAccess; } -:1141: /// 154:1142: @override function isLvalue(): bool { return expression.isLvalue(); } -:1143:} -:1144: -:1145:/// OptAssignExpression -:1146:@final class OptAssignExpression : AssignExpression -:1147:{ -:1148: /// the LHS rewritten as a condition -:1149: @@Semantic var Expression* condition; -:1150: /// 182:1151: @override function setOperator() { operator = optAss; } -:1152:} -:1153: -:1154:/// OrAssignExpression -:1155:@final class OrAssignExpression : AssignExpression -:1156:{ -:1157: /// 22:1158: @override function setOperator() { operator = pipeAss; } -:1159:} -:1160: -:1161:/// OrExpression -:1162:@final class OrExpression : BinaryExpression -:1163:{ -:1164: /// 114:1165: @override function setOperator() { operator = TokenType.pipe; } -:1166:} -:1167: -:1168:/// AndExpression -:1169:@final class OrOrExpression : AndAndExpression -:1170:{ -:1171: /// 1066:1172: @override function setOperator() { operator = orOr; } -:1173:} -:1174: -:1175:/// PosDecExpression -:1176:class PostDecExpression : UnaryExpression -:1177:{ -:1178: /// 172:1179: @override function setOperator() { operator = minMin; } -:1180:} -:1181: -:1182:/// PosDecExpression -:1183:@final class PostIncExpression : PostDecExpression -:1184:{ -:1185: /// 1006:1186: @override function setOperator() { operator = plusPlus; } -:1187:} -:1188: -:1189:/// PreDecExpression -:1190:class PreDecExpression : UnaryExpression -:1191:{ -:1192: /// 222:1193: @override function setOperator() { operator = eopPreDec; } -:1194: /// 104:1195: @final @override function isLvalue(): bool { return true; } -:1196:} -:1197: -:1198:/// PreIncExpression -:1199:@final class PreIncExpression : PreDecExpression -:1200:{ -:1201: /// 324:1202: @override function setOperator() { operator = eopPreInc; } -:1203:} -:1204: -:1205:/// PtrExpression -:1206:@final class PtrExpression : UnaryExpression -:1207:{ -:1208: @constructor function create(Expression* node; Type* t; bool isRewrite) -:1209: { 2652:1210: assert(t.kind == mul); -:1211: 2652:1212: this.operator = eopPtr; 2652:1213: this.expression = getArrayOpResult(node, isRewrite); 2652:1214: this.startPos = node.startPos; 2652:1215: this.type = t; 2652:1216: } -:1217: /// -:1218: @override function setOperator() { assert(0); } -:1219: /// 2485:1220: @override function isLvalue(): bool { return false; } -:1221:} -:1222: -:1223:/// RangeExpression -:1224:@final class RangeExpression : BinaryExpression -:1225:{ -:1226: /// `.type` is used to make the expression globally unusable. -:1227: /// When valid, the actual type is provided by this field. -:1228: @@Semantic var Type* elemType; -:1229: /// -:1230: @override function setOperator() { assert(0); } -:1231: /// -:1232: @constructor function create(var Position startPos; Expression* left = null; -:1233: Expression* right = null; Type* elemType = null; Type* type = null) -:1234: { 2497:1235: this.operator = TokenType.dotDot; 2497:1236: this.startPos = startPos; 2497:1237: this.left = left; 2497:1238: this.right = right; 2497:1239: this.type = type; 2497:1240: this.elemType = elemType; 2497:1241: } -:1242:} -:1243: -:1244:/// RShiftAssignExpression -:1245:@final class RShiftAssignExpression : AssignExpression -:1246:{ -:1247: /// 12:1248: @override function setOperator() { operator = rshiftAss; } -:1249:} -:1250: -:1251:/// LShiftExpression -:1252:@final class RShiftExpression : BinaryExpression -:1253:{ -:1254: /// 24:1255: @override function setOperator() { operator = rShift; } -:1256:} -:1257: -:1258:/// To assign string literals or slice to ref counted strings -:1259:@final class RcaAssignExpression : UnaryExpression -:1260:{ -:1261: /// gives the source pointer -:1262: var Expression* ptr; -:1263: /// gives the source length -:1264: var Expression* length; -:1265: /// gives the temp target -:1266: var Expression* target; -:1267: /// 476:1268: @override function setOperator() { operator = eopRcaAssign; } -:1269: /// -:1270: @override function free() -:1271: { 0:1272: ptr?.free(); 0:1273: length?.free(); 0:1274: target?.free(); 0:1275: super(); 0:1276: } -:1277: /// 238:1278: @override function isLvalue(): bool { return true; } -:1279:} -:1280: -:1281:/// RefCountExpression -:1282:@final class RefCountExpression : UnaryExpression -:1283:{ -:1284: /// map to PropertyKind.refcount_ .. PropertyKind.dup_ -:1285: @@Semantic var RefCountOp subOp; -:1286: /// -:1287: @override function setOperator() { assert(0); } -:1288: /// -:1289: @constructor function create(var Position startPos; Expression* expression; u8 subOp; Type* type) -:1290: { 137:1291: this.operator = eopRefCount; 137:1292: this.startPos = startPos; 137:1293: this.expression = expression; 137:1294: this.subOp = subOp; 137:1295: this.type = type; 137:1296: } -:1297:} -:1298: -:1299:/// SetLengthExpression -:1300:@final class SetLengthExpression : UnaryExpression -:1301:{ -:1302: /// `true` if initializers must be copied, `false` if used as a macro before copy (e.g SliceExp) -:1303: @@Semantic var bool isInitStored; -:1304: /// -:1305: var Expression* newLength; -:1306: /// -:1307: @constructor function create(Expression* expression; Expression* newLength; -:1308: Type* type; bool isInitStored) -:1309: { 300:1310: this.operator = eopSetLength; 300:1311: this.startPos = expression.startPos; 300:1312: this.expression = expression; 300:1313: this.newLength = newLength; 300:1314: this.type = type; 300:1315: this.isInitStored = isInitStored; 300:1316: } -:1317: /// -:1318: @override function free() -:1319: { 0:1320: newLength?.free(); 0:1321: super(); 0:1322: } -:1323: /// -:1324: @override function setOperator() { assert(0); } -:1325: /// -:1326: @override function accept(AstVisitor* visitor) -:1327: { 2:1328: super(visitor); 4:1329: if newLength do visitor.visitExpression(newLength); 2:1330: } -:1331:} -:1332: -:1333:/// SliceExpression -:1334:@final class SliceExpression : UnaryExpression -:1335:{ -:1336: /// If in `slice[] = assignRhs` assignRhs is a single element -:1337: @@Semantic var bool isElemAssign; -:1338: /// if that slice is required without frame pointer -:1339: @@Semantic var bool isStatic; -:1340: /// if that slice looks like a TypeRca definition -:1341: var bool tryAsTypeRca; -:1342: /// `expression.length` but without the side-effect -:1343: @@Semantic var Expression* sourceLength; -:1344: /// `expression.ptr` but without the side-effect -:1345: @@Semantic var Expression* sourcePtr; -:1346: /// The slice, as a {u64, T*}, without the side-effect -:1347: var IdentExpression* result; -:1348: /// If the slice is used in `slice[] = assignRhs` -:1349: @@Semantic var Expression* assignRhs; -:1350: /// left .. right -:1351: var RangeExpression* range; -:1352: /// Required by static slices, e.g initialized with ArrayExps -:1353: @@Semantic var VariableDeclaration* staticPtrProvider; -:1354: /// -:1355: @override function setOperator() { assert(0); } -:1356: /// -:1357: @constructor function create(Position startPos; Expression* expression; -:1358: RangeExpression* range = null) -:1359: { 2155:1360: this.operator = eopSlice; 2155:1361: this.startPos = startPos; 2155:1362: this.expression = expression; 2155:1363: this.range = range; 2155:1364: } -:1365: /// -:1366: @override function free() -:1367: { 7:1368: range?.free(); 7:1369: result?.free(); 7:1370: staticPtrProvider?.free(); 7:1371: super(); 7:1372: } -:1373: /// -:1374: @override function accept(AstVisitor* visitor) -:1375: { 839:1376: super(visitor); 1490:1377: if range do visitor.visitExpression(range); 839:1378: } -:1379: /// as `result` is a lvalue -:1380: @override function isLvalue(): bool -:1381: { 1189:1382: return !isStatic; -:1383: } -:1384: /// -:1385: @override function canInitialize(): bool -:1386: { 12:1387: assert(range && expression); 12:1388: return isStatic || range.left.canInitialize() && range.right.canInitialize() && expression.canInitialize(); -:1389: } -:1390:} -:1391: -:1392:/// StringExpression -:1393:@final class StringExpression : Expression -:1394:{ -:1395: /// -:1396: var Token* value; -:1397: /// -:1398: @constructor function create(var Position startPos; Token* value; Type* type = null) -:1399: { 6862:1400: this.operator = stringLiteral; 6862:1401: this.startPos = startPos; 6862:1402: this.value = value; 6862:1403: this.type = type; 6862:1404: } -:1405: /// 3270:1406: @override function accept(AstVisitor* visitor){} -:1407: /// 60:1408: @override function canInitialize(): bool { return true; } -:1409: /// 541:1410: @override function isLiteral(): bool { return true; } -:1411: /// -:1412: @override function isEqual(Object* other): bool -:1413: { -:1414: assert(0); -:1415: } -:1416:} -:1417: -:1418:/// -:1419:class BinaryExpression : Expression -:1420:{ -:1421: /// -:1422: var Expression* left; -:1423: /// -:1424: var Expression* right; -:1425: /// -:1426: @constructor function create(var Position startPos; Expression* left = null; -:1427: Expression* right = null; Type* type = null; Symbol* symbol = null) -:1428: { 21189:1429: setOperator(); -:1430: 21189:1431: this.startPos = startPos; 21189:1432: this.left = left; 21189:1433: this.right = right; 21189:1434: this.type = type; 21189:1435: this.symbol = symbol; 21189:1436: } -:1437: /// called during construction of @final derived -:1438: @abstract @virtual function setOperator(); -:1439: /// -:1440: @override function free() -:1441: { 859:1442: left?.free(); 859:1443: right?.free(); 859:1444: super(); 859:1445: } -:1446: /// -:1447: @override function accept(AstVisitor* visitor) -:1448: { 33460:1449: if left do visitor.visitExpression(left); 33428:1450: if right do visitor.visitExpression(right); 16730:1451: } -:1452:} -:1453: -:1454:/// SubAssignExpression -:1455:@final class SubAssignExpression : AssignExpression -:1456:{ -:1457: /// 284:1458: @override function setOperator() { operator = minusAss; } -:1459:} -:1460: -:1461:/// SubExpression -:1462:@final class SubExpression : BinaryExpression -:1463:{ -:1464: /// 1876:1465: @override function setOperator() { operator = minus; } -:1466:} -:1467: -:1468:/// SuperExpression -:1469:@final class SuperExpression : Expression -:1470:{ -:1471: /// -:1472: @constructor function create(var Position startPos) -:1473: { 118:1474: this.operator = $super; 118:1475: this.startPos = startPos; 118:1476: } -:1477: /// 111:1478: @override function accept(AstVisitor* visitor){} -:1479: /// 1:1480: @override function isAssignable(): bool {return false;} -:1481:} -:1482: -:1483:/// ThisExpression -:1484:@final class ThisExpression : IdentExpression -:1485:{ -:1486: /// -:1487: @constructor function create(var Position startPos) -:1488: { 2837:1489: this.operator = TokenType.$this; 2837:1490: this.startPos = startPos; 2837:1491: this.identifier = thisToken(); 2837:1492: } -:1493: /// 712:1494: @override function accept(AstVisitor* visitor){} -:1495: /// 1:1496: @override function isAssignable(): bool {return false;} -:1497:} -:1498: -:1499:/// TupleExpression -:1500:@final class TupleExpression : Expression -:1501:{ -:1502: /// if made of expressions that are all usable as static initializer -:1503: var bool allCanInitialize; -:1504: /// if made of expressions that are all lvalues -:1505: var bool allLvalues; -:1506: /// if allLvalues and also used as AssignExpression LHS -:1507: var bool isAssignLhs; -:1508: /// -:1509: var Expression*[+] expressions; -:1510: /// if it's in a function and contains non constant values -:1511: @@Semantic var VariableDeclaration* value; -:1512: /// -:1513: @constructor function create(var Position startPos; Expression*[] expressions) -:1514: { 183:1515: this.operator = TokenType.rightParen; 183:1516: this.startPos = startPos; 183:1517: this.expressions = expressions; 183:1518: } -:1519: /// -:1520: @override function free() -:1521: { 10:1522: foreach var auto e in expressions do 17:1523: e.free(); 10:1524: expressions.decref; 10:1525: super(); 10:1526: } -:1527: /// -:1528: @override function accept(AstVisitor* visitor) -:1529: { 137:1530: foreach var auto e in expressions do 300:1531: visitor.visitExpression(e); 137:1532: } -:1533: /// -:1534: @override function isLvalue(): bool -:1535: { 179:1536: return value != null || allLvalues; -:1537: } -:1538: /// 14:1539: @override function canInitialize(): bool { return allCanInitialize; } -:1540:} -:1541: -:1542:/// TypeExpression -:1543:@final class TypeExpression : Expression -:1544:{ -:1545: /// flag allowing to properly reject the expression when used as a primary only. -:1546: @@Semantic var bool raw; -:1547: /// the wrapped type -:1548: var Type* wrapped; -:1549: /// -:1550: @constructor function create(var Position startPos; Type* type = null; bool solved = false; bool raw = true) -:1551: { 3635:1552: this.operator = eopType; 3635:1553: this.raw = raw; 3635:1554: this.startPos = startPos; 3635:1555: this.wrapped = type; 3635:1556: if solved do -:1557: { 3008:1558: this.type = wrapped; 3008:1559: this.type.progress = SemanticProgress.done; -:1560: } 3635:1561: } -:1562: /// -:1563: @override function free() -:1564: { 21:1565: wrapped?.free(); 21:1566: super(); 21:1567: } -:1568: /// -:1569: @override function accept(AstVisitor* visitor) -:1570: { 1180:1571: if wrapped do visitor.visitType(wrapped); 590:1572: } -:1573: /// -:1574: @override function isEqual(Object* other): bool -:1575: { -:1576: assert(0, "comparse this.type with another type instead"); -:1577: } -:1578:} -:1579: -:1580:/// UnaryExpression -:1581:class UnaryExpression : Expression -:1582:{ -:1583: /// -:1584: var Expression* expression; -:1585: /// -:1586: @constructor function create(var Position startPos; Expression* expression = null; -:1587: Type* type = null; Symbol* symbol = null) -:1588: { 19797:1589: setOperator(); -:1590: 19797:1591: this.startPos = startPos; 19797:1592: this.expression = expression; 19797:1593: this.type = type; 19797:1594: this.symbol = symbol; 19797:1595: } -:1596: /// called during construction of @final derived -:1597: @abstract @virtual function setOperator(); -:1598: /// -:1599: @override function free() -:1600: { 3567:1601: expression?.free(); 3567:1602: super(); 3567:1603: } -:1604: /// -:1605: @override function accept(AstVisitor* visitor) -:1606: { 76627:1607: if expression do visitor.visitExpression(expression); 38373:1608: } -:1609:} -:1610: -:1611:/// VersionIdentExpression -:1612:@final class VersionIdentExpression : Expression -:1613:{ -:1614: /// if `identifier` is set and resolved to `true` -:1615: @@Semantic var bool isDefined; -:1616: /// -:1617: var Token* identifier; -:1618: /// -:1619: @constructor function create(var Position startPos; Token* identifier; Type* type) -:1620: { 213:1621: this.operator = $version; 213:1622: this.startPos = startPos; 213:1623: this.identifier = identifier; 213:1624: this.type = type; 213:1625: } -:1626: /// 12:1627: @override function accept(AstVisitor* visitor) { } -:1628:} -:1629: -:1630:/// XorAssignExpression -:1631:@final class XorAssignExpression : AssignExpression -:1632:{ -:1633: /// 22:1634: @override function setOperator() { operator = xorAss; } -:1635:} -:1636: -:1637:/// XorExpression -:1638:@final class XorExpression : BinaryExpression -:1639:{ -:1640: /// 18:1641: @override function setOperator() { operator = xor; } -:1642:} -:1643: -:1644:/// Returns: the most nested unary that's not a CastExp -:1645:function stripCast(Expression* node): Expression* -:1646:{ 22088:1647: if var CastExpression* ce = asCastExp(node) do 0:1648: return stripCast(ce.expression); 11044:1649: return node; -:1650:} -:1651: -:1652:/// Returns: the integer literal in node, stripping casts -:1653:function getIntLiteral(Expression* node): IntegerExpression* -:1654:{ 57999:1655: assert(node); 115998:1656: if var IntegerExpression* ie = asIntegerExp(node) do 49382:1657: return ie; 17234:1658: else do if var CastExpression* ce = asCastExp(node) do 1248:1659: return getIntLiteral(ce.expression); 14738:1660: else do if var EnumMember* em = symToEnumMember(node.symbol) do 1693:1661: return getIntLiteral(em.value); 5676:1662: return null; -:1663:} -:1664: -:1665:/** -:1666: * Array operations such as TidExp and SliceExp internally use helper nodes -:1667: * such as LengthExp or PtrExp, that are not part of the AST, they -:1668: * simplify the backend. -:1669: * -:1670: * These nodes must not repeat the side effect of the array operation. -:1671: * -:1672: * `getArrayOpResult` allows to select the right expression depending on if -:1673: * the side effect must be triggered or not. -:1674: * -:1675: * for example: -:1676: * -:1677: * - `a[0..1]` is rewritten `a.ptr[0..1]`, in this case the new `a.ptr` must -:1678: * trigger the side effect. -:1679: * - `(a ~ b)[]` is rewritten `(a ~ b).ptr[0..(a ~ b).length]`, in this case the -:1680: * new `(a ~ b).ptr` must trigger the side effect but not `(a ~ b).length`, -:1681: * which will rather use a special variable associated to the `(a ~ b)` TidExp. -:1682: * - another notable case is when rvalues are turned in lvalues using a temporary: -:1683: * `call()[0..1]` is rewritten `(var T __temp, __temp = call()).ptr[0..1]`, -:1684: * in this case the new `.ptr` must be done on `__tmp` and not on the DeclExp. -:1685: * -:1686: * Params: -:1687: * node = The expression that contains a side-effect -:1688: * skipSideEffect = if the side effect must be skipped -:1689: * -:1690: * Returns: The right exp. -:1691: */ -:1692:function getArrayOpResult(Expression* node; bool skipSideEffect): Expression* -:1693:{ 11748:1694: if var DeclExpression* de = asDeclExp(node) do 630:1695: return getArrayOpResult(de.expression, skipSideEffect); 10488:1696: if var ConcatExpression* ce = asConcatExp(node) do 122:1697: return skipSideEffect ? ce.result else ce; 10244:1698: if var SliceExpression* se = asSliceExp(node) do 505:1699: return skipSideEffect && se.result ? se.result else se; 9234:1700: if var AssignExpression* ae = asAssignExp(node) do 496:1701: return skipSideEffect ? ae.left else ae; 4121:1702: return node; -:1703:} -:1704: -:1705:/** Returns: the FunctionDeclaration which a call expression operates on. -:1706: * The result can be the declaration used for a TypeFunction. -:1707: * The result is supposed to be a type reference that give the return type and -:1708: * the parameter types and storage classes, it is not the value to call. */ -:1709:function getFuncDeclForCall(CallExpression* node): FunctionDeclaration* -:1710:{ -:1711: //assert (node.expression.symbol, "called too early"); -:1712: 36703:1713: if node.fd do 13481:1714: return node.fd; -:1715: 23222:1716: if node.expression.symbol do -:1717: { 46376:1718: if var auto fd = symToFuncDecl(node.expression.symbol) do 22662:1719: return fd; -:1720: } 1120:1721: if var TypeFunction* tf = node.expression.type.asTypeFunction() do -:1722: { 2:1723: return tf.declaration; -:1724: } 1116:1725: if var TypePointer* tp = node.expression.type.asTypePointer() do -:1726: { 392:1727: if var TypeFunction* tf = tp.modified.asTypeFunction() do 196:1728: return tf.declaration; -:1729: } 362:1730: return null; -:1731:} <<<<<< EOF # path=src/styx/ast/formatter.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/ast/formatter.sx -: 1:unit styx.ast.formatter; -: 2: -: 3:@private import -: 4: system, -: 5: styx.ast.base, -: 6: styx.ast.visitor, -: 7: styx.ast.declarations, -: 8: styx.ast.expressions, -: 9: styx.ast.statements, -: 10: styx.ast.types, -: 11: styx.symbol, -: 12: styx.token, -: 13: ; -: 14: -: 15:enum FormatterOption -: 16:{ -: 17: noBody, // dont format function and aggregate bodies -: 18: binParens, // always but binary exp between parens -: 19: nullTerminates, -: 20:} -: 21: -: 22:alias FormatterOptions = bool[FormatterOption]; -: 23: -: 24:/// formatter options used by the compiler messages -: 25:const FormatterOptions errorMode = [noBody, nullTerminates]; -: 26: -: 27:/// formatter options used to test the formatter -: 28:const FormatterOptions testMode = [binParens]; -: 29: -: 30:/// formatter options used to build internal strings -: 31:const FormatterOptions internalMode = [noBody]; -: 32: -: 33:alias formatType = apply(formatNode, Type); -: 34:alias formatDeclaration = apply(formatNode, Declaration); -: 35:alias formatStatement = apply(formatNode, Statement); -: 36:alias formatExpression = apply(formatNode, Expression); -: 37:alias formatDynamic = apply(formatNode, AstNode); -: 38: -: 39:overload format -: 40:{ -: 41: formatType, -: 42: formatDeclaration, -: 43: formatStatement, -: 44: formatExpression, -: 45: formatDynamic, -: 46:} -: 47: -: 48:protection (private) -: 49: -: 50:function formatNode[T](T* node; const FormatterOptions options = errorMode): s8[+] -: 51:{ 63662: 52: var AstFormatter formatter = AstFormatter.create(options); -: 53: 60031: 54: if echo(is, T, Type) do formatter.visitConcreteType(node); 352: 55: else do if echo(is, T, Declaration) do formatter.visitConcreteDeclaration(node); 2: 56: else do if echo(is, T, Statement) do formatter.visitConcreteStatement(node); 3253: 57: else do if echo(is, T, Expression) do formatter.visitExpression(node); 24: 58: else do if echo(is, T, AstNode) do formatter.visitAstNode(node); -: 59: 63662: 60: var s8[+] result = formatter.result.array(); 63662: 61: if nullTerminates in options do 62761: 62: result ~= 0; -: 63: 63662: 64: return result; -: 65:} -: 66: -: 67:@final class AstFormatter : AstVisitor -: 68:{ -: 69: var FormatterOptions options; -: 70: var s32 indentLevel; -: 71: var Appender:[s8, 128] result; -: 72: -: 73: @constructor function create(FormatterOptions options) -: 74: { 63662: 75: this.options= options; 63662: 76: } -: 77: -: 78: @destructor function destroy() -: 79: { 127324: 80: result.destroy(); 127324: 81: } -: 82: -: 83: function fill(s8 c; usize count) -: 84: { 1983: 85: foreach const auto i in 0 .. count do result.append(c); 641: 86: } -: 87: -: 88: function growIndentLevel() -: 89: { 116: 90: indentLevel += 1; 116: 91: } -: 92: -: 93: function shrinkIndentLevel() -: 94: { 116: 95: indentLevel -= 1; 116: 96: } -: 97: -: 98: function indent() -: 99: { 811: 100: foreach const auto i in 0 .. indentLevel do 233: 101: fill(" ", 4); 811: 102: } -: 103: -: 104: function openParen(Expression* e) -: 105: { 16478: 106: if e.parens != 0 do fill("(", e.parens); 16274: 107: } -: 108: -: 109: function closeParen(Expression* e) -: 110: { 16478: 111: if e.parens != 0 do fill(")", e.parens); 16274: 112: } -: 113: -: 114: function newLine() -: 115: { 273: 116: result.append("\n"); 273: 117: } -: 118: -: 119: function semicolon() -: 120: { 123: 121: result.append(";"); 123: 122: } -: 123: -: 124: function semicolonAndNewLine() -: 125: { 115: 126: result.appendN(";\n"); 115: 127: } -: 128: -: 129: function space() -: 130: { 3907: 131: result.append(" "); 3907: 132: } -: 133: -: 134: function addDeclarationName(Declaration* node) -: 135: { 1302: 136: if node.genericParameters && node.genericParameters.applied() do -: 137: { 287: 138: visitToken(node.baseGeneric.name); 287: 139: result.appendN(":["); 287: 140: foreach (const auto i; var auto p) in node.genericParameters.parameters do -: 141: { 568: 142: visitConcreteExpression(p.originalExp); 568: 143: if i != node.genericParameters.parameters.length - 1 do 281: 144: result.append(","); -: 145: } 287: 146: result.append("]"); -: 147: } -: 148: else do -: 149: { 1015: 150: if node.name do 834: 151: visitToken(node.baseGeneric ? node.baseGeneric.name else node.name); 1015: 152: if node.genericParameters do 19: 153: visitGenericParameters(node.genericParameters); -: 154: } 1302: 155: } -: 156: -: 157: @override function visitAddAssignExpression(const AddAssignExpression* node) -: 158: { 8: 159: visitAssignExpression(node); 8: 160: } -: 161: -: 162: @override function visitAddExpression(const AddExpression* node) -: 163: { 89: 164: visitBinaryExpression(node); 89: 165: } -: 166: -: 167: function visitAggregateDeclaration(AggregateDeclaration* node; const s8[] keyword) -: 168: { 60: 169: indent(); 71: 170: if node.attributes do visitAttributes(node.attributes); 61: 171: if node.isStatic() do result.appendN("static "); 60: 172: result.appendN(keyword); 60: 173: space(); 60: 174: addDeclarationName(node); 60: 175: if node.inheritanceList.length do -: 176: { 13: 177: result.appendN(": "); 13: 178: foreach (const auto i; var Type* c) in node.inheritanceList do -: 179: { 32: 180: if var auto ta = c.asTypeAggregate() do 12: 181: addDeclarationName(ta.declaration); 4: 182: else do visitConcreteType(c); 16: 183: if i != node.inheritanceList.length - 1 do 3: 184: result.appendN(", "); -: 185: } -: 186: } 60: 187: if !node.body do 3: 188: semicolon(); 57: 189: else do if FormatterOption.noBody !in options do -: 190: { 11: 191: newLine(); 11: 192: indent(); 11: 193: result.appendN("{\n"); 11: 194: growIndentLevel(); 22: 195: if node.body do visitDeclarations(node.body); 11: 196: shrinkIndentLevel(); 11: 197: indent(); 11: 198: result.append("}"); -: 199: } 60: 200: } -: 201: -: 202: @override function visitAliasDeclaration(AliasDeclaration* node) -: 203: { 51: 204: indent(); 57: 205: if node.attributes do visitAttributes(node.attributes); 51: 206: result.appendN("alias "); 51: 207: visitToken(node.name); 51: 208: result.appendN(" = "); 98: 209: if node.type do visitConcreteType(node.type); 8: 210: else do if node.exp do visitConcreteExpression(node.exp); 51: 211: } -: 212: -: 213: @override function visitAndAndExpression(const AndAndExpression* node) -: 214: { 16: 215: visitBinaryExpression(node); 16: 216: } -: 217: -: 218: @override function visitAndAssignExpression(const AndAssignExpression* node) -: 219: { 1: 220: visitAssignExpression(node); 1: 221: } -: 222: -: 223: @override function visitAndExpression(const AndExpression* node) -: 224: { 3: 225: visitBinaryExpression(node); 3: 226: } -: 227: -: 228: @override function visitApplyExpression(ApplyExpression* node) -: 229: { 38: 230: if node.postStyle do -: 231: { 17: 232: visitConcreteExpression(node.generic); 17: 233: result.appendN(":["); -: 234: } -: 235: else do -: 236: { 21: 237: result.appendN("apply("); 21: 238: visitConcreteExpression(node.generic); 21: 239: result.appendN(", "); -: 240: } 38: 241: var auto args = node.arguments[]; 38: 242: foreach (const auto i; var auto a) in args do -: 243: { 50: 244: visitConcreteExpression(a); 50: 245: if i != args.length - 1 do 12: 246: result.appendN(", "); -: 247: } 38: 248: result.appendN(node.postStyle ? "]"[] else ")"[]); 38: 249: } -: 250: -: 251: @override function visitArrayExpression(ArrayExpression* node) -: 252: { 59: 253: openParen(node); 59: 254: result.append("["); 59: 255: foreach (const auto i; var auto e) in node.items do -: 256: { 126: 257: visitConcreteExpression(e); 126: 258: if i != node.items.length - 1 do 68: 259: result.appendN(", "); -: 260: } 59: 261: result.append("]"); 59: 262: closeParen(node); 59: 263: } -: 264: -: 265: @override function visitAsmExpression(AsmExpression* node) -: 266: { 2: 267: openParen(node); 2: 268: result.appendN("asm(\""); 2: 269: result.appendN(node.code.text()); 2: 270: result.append(`"`); 2: 271: if node.constraint do -: 272: { 2: 273: result.appendN(", \""); 2: 274: result.appendN(node.constraint.text()); 2: 275: result.append(`"`); -: 276: } 2: 277: foreach var auto a in node.arguments do -: 278: { 2: 279: result.appendN(", "); 2: 280: visitConcreteExpression(a); -: 281: } 2: 282: result.append(")"); 2: 283: if !isTypeVoid(node.returnType) do -: 284: { 2: 285: result.appendN(": "); 2: 286: visitConcreteType(node.returnType); -: 287: } 2: 288: closeParen(node); 2: 289: } -: 290: -: 291: @override function visitAssertStatement(const AssertStatement* node) -: 292: { 2: 293: indent(); 2: 294: result.appendN("assert("); 2: 295: node.accept(this); 2: 296: result.appendN(");"); 2: 297: } -: 298: -: 299: @override function visitAssignExpression(AssignExpression* node) -: 300: { 111: 301: openParen(node); 222: 302: if node.left do visitConcreteExpression(node.left); 111: 303: if node.right do -: 304: { 111: 305: space(); 111: 306: result.appendN(tokenString[node.operator]); 111: 307: space(); 111: 308: visitConcreteExpression(node.right); -: 309: } 111: 310: closeParen(node); 111: 311: } -: 312: -: 313: @override function visitAtExpression(const AtExpression* node) -: 314: { 97: 315: visitPreExpression(node); 97: 316: } -: 317: -: 318: @override function visitAttributes(Attributes* node) -: 319: { 66: 320: foreach var NoArgAttribute noa in NoArgAttribute do 726: 321: if noa in node.noArgAttributes do -: 322: { 38: 323: result.appendN(noArgAttributeStrings[noa]); 38: 324: space(); -: 325: } 66: 326: node.accept(this); 66: 327: } -: 328: -: 329: @override function visitAttribute(Attribute* node) -: 330: { 37: 331: result.appendN(node.isUser ? "@@" else "@"[]); 37: 332: result.appendN(node.identifier.text()); 37: 333: if node.arguments.length do -: 334: { 8: 335: result.append("("); 8: 336: foreach (const auto i; var auto p) in node.arguments do -: 337: { 10: 338: visitConcreteExpression(p); 10: 339: if i != node.arguments.length - 1 do 2: 340: result.appendN(", "); -: 341: } 8: 342: result.append(")"); -: 343: } 37: 344: space(); 37: 345: } -: 346: -: 347: @override function visitBinaryExpression(BinaryExpression* node) -: 348: { 1538: 349: openParen(node); 1538: 350: const bool p = FormatterOption.binParens in options; 1576: 351: if p do result.append("("); 3076: 352: if node.left do visitConcreteExpression(node.left); 1538: 353: space(); 1538: 354: result.appendN(tokenString[node.operator]); 1538: 355: space(); 3075: 356: if node.right do visitConcreteExpression(node.right); 1576: 357: if p do result.append(")"); 1538: 358: closeParen(node); 1538: 359: } -: 360: -: 361: @override function visitBlockStatement(BlockStatement* node) -: 362: { 92: 363: if node.isSingle do -: 364: { 12: 365: growIndentLevel(); 12: 366: node.accept(this); 12: 367: shrinkIndentLevel(); -: 368: } -: 369: else do -: 370: { 80: 371: indent(); 80: 372: result.appendN("{\n"); 80: 373: growIndentLevel(); 80: 374: node.accept(this); 80: 375: shrinkIndentLevel(); 80: 376: indent(); 80: 377: result.appendN("}\n"); -: 378: } 92: 379: } -: 380: -: 381: @override function visitBoolExpression(BoolExpression* node) -: 382: { 151: 383: openParen(node); 151: 384: result.appendN(node.value ? "true"[] else "false"[]); 151: 385: closeParen(node); 151: 386: } -: 387: -: 388: @override function visitBreakOnStatement(const BreakOnStatement* node) -: 389: { 1: 390: indent(); 1: 391: result.appendN("break on"); 1: 392: semicolonAndNewLine(); 1: 393: } -: 394: -: 395: @override function visitBreakStatement(BreakStatement* node) -: 396: { 3: 397: indent(); 3: 398: result.appendN("break"); 3: 399: if node.$label do -: 400: { 3: 401: result.appendN(" @"); 3: 402: result.appendN(node.$label.text()); -: 403: } 3: 404: if node.expression do -: 405: { 3: 406: result.appendN(node.$label ? ", "[] else " "[]); 3: 407: visitConcreteExpression(node.expression); -: 408: } 3: 409: semicolon(); 3: 410: } -: 411: -: 412: @override function visitCallExpression(CallExpression* node) -: 413: { 439: 414: openParen(node); 439: 415: if node.isThisAdded do -: 416: { 99: 417: if !node.fd?.getAtConstructor() do -: 418: { 84: 419: visitConcreteExpression(node.arguments.ptr[0]); 84: 420: result.append("."); -: 421: } -: 422: } 878: 423: if node.expression do visitConcreteExpression(node.expression); 439: 424: result.append("("); 439: 425: var Expression*[] args = node.arguments[]; 439: 426: foreach (const auto i; var auto p) in args do -: 427: { 451: 428: if i == 0 && node.isThisAdded do 99: 429: continue; 352: 430: visitConcreteExpression(p); 352: 431: if i != args.length - 1 do 93: 432: result.appendN(", "); -: 433: } 439: 434: result.append(")"); 439: 435: closeParen(node); 439: 436: } -: 437: -: 438: @override function visitCastExpression(CastExpression* node) -: 439: { 622: 440: openParen(node); 1244: 441: if node.expression do visitConcreteExpression(node.expression); 622: 442: result.append(":"); 1244: 443: if node.toType do visitConcreteType(node.toType); 622: 444: closeParen(node); 622: 445: } -: 446: -: 447: @override function visitClassDeclaration(const ClassDeclaration* node) -: 448: { 23: 449: visitAggregateDeclaration(node, "class"); 23: 450: } -: 451: -: 452: @override function visitCmpExpression(const CmpExpression* node) -: 453: { 1271: 454: visitBinaryExpression(node); 1271: 455: } -: 456: -: 457: @override function visitConcatAssignExpression(const ConcatAssignExpression* node) -: 458: { 2: 459: visitAssignExpression(node); 2: 460: } -: 461: -: 462: @override function visitConcatExpression(const ConcatExpression* node) -: 463: { 3: 464: visitBinaryExpression(node); 3: 465: } -: 466: -: 467: @override function visitConditionalExpression(ConditionalExpression* node) -: 468: { 11: 469: openParen(node); 22: 470: if node.condition do visitConcreteExpression(node.condition); 11: 471: result.appendN(" ? "); 22: 472: if node.thenExpression do visitConcreteExpression(node.thenExpression); 11: 473: result.appendN(" else "); 22: 474: if node.elseExpression do visitConcreteExpression(node.elseExpression); 11: 475: closeParen(node); 11: 476: } -: 477: -: 478: @override function visitContinueOnStatement(ContinueOnStatement* node) -: 479: { 2: 480: indent(); 2: 481: result.appendN("continue on"); 2: 482: if node.targetMatch do -: 483: { 1: 484: space(); 1: 485: node.accept(this); -: 486: } 1: 487: else do if node.isElseTargeted do 1: 488: result.appendN(" else"); 2: 489: semicolonAndNewLine(); 2: 490: } -: 491: -: 492: @override function visitContinueStatement(ContinueStatement* node) -: 493: { 2: 494: indent(); 2: 495: result.appendN("continue"); 2: 496: if node.$label do -: 497: { 1: 498: result.appendN(" @"); 1: 499: result.appendN(node.$label.text()); -: 500: } 2: 501: if node.expression do -: 502: { 2: 503: result.appendN(node.$label ? ", "[] else " "[]); 2: 504: visitConcreteExpression(node.expression); -: 505: } 2: 506: semicolon(); 2: 507: } -: 508: -: 509: @override function visitDeclExpression(DeclExpression* node) -: 510: { -: 511: var bool isVarWritten; 62: 512: result.append("("); 124: 513: if var VariableDeclaration* vd = symToVarDecl(node.declaration.symbol) do -: 514: { 62: 515: result.appendN("var "); 62: 516: visitConcreteType(vd.type); 62: 517: space(); 62: 518: visitToken(node.declaration.name); 62: 519: isVarWritten = true; -: 520: } 62: 521: if isVarWritten && node.expression do 62: 522: result.appendN(", "); 62: 523: if node.expression do 62: 524: visitConcreteExpression(node.expression); 62: 525: result.append(")"); 62: 526: } -: 527: -: 528: @override function visitDeclaration(Declaration* node) -: 529: { 144: 530: const FunctionDeclaration* fd = node:FunctionDeclaration*; 144: 531: const VariableDeclaration* vd = node:VariableDeclaration*; 144: 532: const bool needsSemicolon = (fd && !fd.body) || vd || 94: 533: node.kind == $alias || node.kind == $import || node.kind == $label || node.kind == eopLambda; 184: 534: if vd do indent(); 144: 535: visitConcreteDeclaration(node); 209: 536: if needsSemicolon do semicolon(); 288: 537: if noBody !in options do newLine(); 144: 538: } -: 539: -: 540: @override function visitDeleteExpression(DeleteExpression* node) -: 541: { 2: 542: openParen(node); 2: 543: result.appendN("delete "); 2: 544: if node.deallocator do -: 545: { 1: 546: result.append("("); 1: 547: visitConcreteExpression(node.expression); 1: 548: result.appendN(", "); 1: 549: visitConcreteExpression(node.deallocator); 1: 550: result.append(")"); -: 551: } 1: 552: else do visitConcreteExpression(node.expression); 2: 553: closeParen(node); 2: 554: } -: 555: -: 556: @override function visitDerefExpression(const DerefExpression* node) -: 557: { 81: 558: visitPreExpression(node); 81: 559: } -: 560: -: 561: @override function visitDivAssignExpression(const DivAssignExpression* node) -: 562: { 1: 563: visitAssignExpression(node); 1: 564: } -: 565: -: 566: @override function visitDivExpression(const DivExpression* node) -: 567: { 3: 568: visitBinaryExpression(node); 3: 569: } -: 570: -: 571: @override function visitDollarExpression(const DollarExpression* node) -: 572: { 33: 573: result.append("$"); 33: 574: } -: 575: -: 576: @override function visitDotExpression(DotExpression* node) -: 577: { 483: 578: openParen(node); 966: 579: if node.expression do visitConcreteExpression(node.expression); 483: 580: result.append("."); 966: 581: if node.dotted do visitConcreteExpression(node.dotted); 483: 582: closeParen(node); 483: 583: } -: 584: -: 585: @override function visitEchoExpression(EchoExpression* node) -: 586: { 121: 587: openParen(node); 121: 588: result.appendN("echo("); 121: 589: result.appendN(node.command.text()); 121: 590: foreach (const auto i; var auto a) in node.arguments do -: 591: { 382: 592: if i != node.arguments.length do result.appendN(", "); 191: 593: visitConcreteExpression(a); -: 594: } 121: 595: result.append(")"); 121: 596: closeParen(node); 121: 597: } -: 598: -: 599: @override function visitEnumDeclaration(EnumDeclaration* node) -: 600: { 7: 601: indent(); 8: 602: if node.attributes do visitAttributes(node.attributes); 7: 603: result.appendN("enum "); 7: 604: visitToken(node.name); 7: 605: if node.type do -: 606: { 7: 607: result.appendN(": "); 7: 608: visitConcreteType(node.type); -: 609: } 7: 610: if isEponymous in node.flags do -: 611: { 1: 612: result.appendN(" = "); 1: 613: visitConcreteExpression(node.members[0].value); 1: 614: result.appendN(";\n"); 1: 615: return; -: 616: } 6: 617: if noBody !in options do -: 618: { 1: 619: newLine(); 1: 620: indent(); 1: 621: result.appendN("{\n"); 1: 622: growIndentLevel(); 1: 623: foreach (const auto i; var auto m) in node.members do -: 624: { 2: 625: indent(); 2: 626: visitEnumMember(m); 3: 627: if i != node.members.length - 1 do result.appendN(",\n"); 1: 628: else do newLine(); -: 629: } 1: 630: shrinkIndentLevel(); 1: 631: indent(); 1: 632: result.append("}"); -: 633: } 6: 634: } -: 635: -: 636: @override function visitEnumMember(EnumMember* node) -: 637: { 3: 638: visitToken(node.name); 3: 639: if node.value do -: 640: { 3: 641: result.appendN(" = "); 3: 642: visitConcreteExpression(node.value); -: 643: } 3: 644: } -: 645: -: 646: @override function visitExpressionAlias(ExpressionAlias* node) -: 647: { 1: 648: result.appendN("alias "); 1: 649: result.appendN(node.name.text()); 1: 650: result.appendN(" => "); 1: 651: visitConcreteExpression(node.expression); 1: 652: } -: 653: -: 654: @override function visitExpressionStatement(ExpressionStatement* node) -: 655: { 46: 656: indent(); 92: 657: if node.expression do visitConcreteExpression(node.expression); 46: 658: semicolon(); 46: 659: } -: 660: -: 661: @override function visitFloatExpression(FloatExpression* node) -: 662: { 101: 663: openParen(node); 101: 664: if !node.tok do -: 665: { -: 666: @noinit var s8[256] buff; 15: 667: const usize len = snprintf(buff.ptr, buff.length, "%f", node.value); 15: 668: assert(len < 256); 15: 669: result.appendN(buff[0 .. len]); -: 670: } 86: 671: else do result.appendN(node.tok.text()[]); 101: 672: closeParen(node); 101: 673: } -: 674: -: 675: @override function visitForeachStatement(ForeachStatement* node) -: 676: { 7: 677: indent(); 7: 678: result.appendN("foreach "); 13: 679: if node.hasParens do result.append("("); 7: 680: foreach (const auto i; var auto v) in node.variables do -: 681: { 8: 682: visitVariableDeclaration(v); 9: 683: if i != node.variables.length - 1 do result.appendN("; "); -: 684: } 13: 685: if node.hasParens do result.append(")"); 7: 686: result.appendN(" in "); 7: 687: if node.expression do -: 688: { 7: 689: if node.isReversed do result.append("("); 7: 690: visitConcreteExpression(node.expression); 7: 691: if node.isReversed do result.appendN(").reverse"); -: 692: } 7: 693: result.appendN(" do\n"); 7: 694: visitBlockStatement(node.blockStatement); 7: 695: } -: 696: -: 697: @override function visitFunctionDeclaration(FunctionDeclaration* node) -: 698: { 315: 699: indent(); 356: 700: if node.attributes do visitAttributes(node.attributes); 315: 701: result.appendN(storageClassesText(node.stc)); 315: 702: result.appendN("function "); 315: 703: if node.externalAggregate do -: 704: { 1: 705: result.appendN(node.externalAggregate.text()); 1: 706: result.append("."); -: 707: } 315: 708: addDeclarationName(node); 315: 709: result.append("("); 315: 710: const bool isCeeVariadic = FunctionFlag.isCeeVariadic in node.flags; 315: 711: foreach (const auto i; var auto p) in node.parameters do -: 712: { 274: 713: visitVariableDeclaration(p); 355: 714: if i != node.parameters.length - 1 && !isCeeVariadic do result.appendN("; "); -: 715: } 320: 716: if isCeeVariadic do result.appendN("..."); 315: 717: result.append(")"); 315: 718: if !isTypeVoid(node.returnType) do -: 719: { 76: 720: result.appendN(":"); 76: 721: visitConcreteType(node.returnType); -: 722: } 315: 723: if (noBody !in options) do -: 724: { 65: 725: if node.body do -: 726: { 55: 727: newLine(); 55: 728: visitConcreteStatement(node.body); -: 729: } 10: 730: else do if node.asmBody do -: 731: { 1: 732: result.appendN(" = asm"); 1: 733: newLine(); 1: 734: visitConcreteExpression(node.asmBody); 1: 735: newLine(); 1: 736: semicolon(); -: 737: } -: 738: } 315: 739: } -: 740: -: 741: @override function visitGenericParameter(GenericParameter* node) -: 742: { 25: 743: if node.valueType do -: 744: { 2: 745: visitConcreteType(node.valueType); 2: 746: space(); -: 747: } 25: 748: result.appendN(node.name.text()); 25: 749: if node.appliedExp do -: 750: { 1: 751: result.appendN(" = "); 1: 752: visitConcreteExpression(node.appliedExp); -: 753: } 24: 754: else do if node.appliedType do -: 755: { 1: 756: result.appendN(" = :"); 1: 757: visitConcreteType(node.appliedType); -: 758: } 25: 759: } -: 760: -: 761: @override function visitGenericParameters(GenericParameters* node) -: 762: { 19: 763: result.append("["); 19: 764: var auto pp = node.parameters[]; 19: 765: foreach (const auto i; var auto p) in pp do -: 766: { 24: 767: visitConcreteDeclaration(p); 29: 768: if i != pp.length - 1 do result.appendN(", "); -: 769: } 19: 770: result.append("]"); 19: 771: } -: 772: -: 773: @override function visitGotoStatement(GotoStatement* node) -: 774: { 1: 775: indent(); 1: 776: result.appendN("goto"); 1: 777: result.appendN(" @"); 1: 778: result.appendN(node.$label.text()); 1: 779: if node.expression do -: 780: { 1: 781: result.appendN(", "); 1: 782: visitConcreteExpression(node.expression); -: 783: } 1: 784: semicolon(); 1: 785: } -: 786: -: 787: @override function visitIdentExpression(IdentExpression* node) -: 788: { 3419: 789: openParen(node); 3419: 790: if node.identifier.keywordAsIdentifier() do 8: 791: result.append("$"); 3419: 792: result.appendN(node.identifier.text()); 3419: 793: closeParen(node); 3419: 794: } -: 795: -: 796: @override function visitIfElseStatement(IfElseStatement* node) -: 797: { 13: 798: indent(); 13: 799: result.appendN("if "); 13: 800: if node.condition do -: 801: { 11: 802: visitConcreteExpression(node.condition); 11: 803: result.appendN(" do\n"); -: 804: } 2: 805: else do if node.ifVariable do -: 806: { 4: 807: if node.hasParens do result.append("("); 2: 808: visitVariableDeclaration(node.ifVariable); 4: 809: if node.hasParens do result.append(")"); 2: 810: result.appendN(" do\n"); -: 811: } 13: 812: visitBlockStatement(node.thenBlock); 13: 813: if node.elseBlock do -: 814: { 2: 815: indent(); 2: 816: result.appendN("else do\n"); 2: 817: visitBlockStatement(node.elseBlock); -: 818: } 13: 819: } -: 820: -: 821: @override function visitImportDeclaration(ImportDeclaration* node) -: 822: { 5: 823: indent(); 6: 824: if node.attributes do visitAttributes(node.attributes); 5: 825: result.appendN("import "); 5: 826: if !node.isSelective do -: 827: { 4: 828: foreach (const auto i; var auto p) in node.importList do -: 829: { 6: 830: const bool isLast = i == node.importList.length - 1; 6: 831: visitTypeIdentifier(p); 8: 832: if !isLast do result.appendN(", "); -: 833: } 4: 834: return; -: 835: } 1: 836: foreach (const auto i; var auto p) in node.importList do -: 837: { 3: 838: const bool isSym = i != node.importList.length - 1; 3: 839: const bool isLastSym = i == node.importList.length - 2; 3: 840: visitTypeIdentifier(p); 3: 841: if isSym && !isLastSym do 1: 842: result.appendN(", "); 2: 843: else do if isLastSym do 1: 844: result.appendN(" in "); -: 845: } 1: 846: } -: 847: -: 848: @override function visitInExpression(InExpression* node) -: 849: { 29: 850: openParen(node); 29: 851: result.append("("); 58: 852: if node.right do visitConcreteExpression(node.right); 29: 853: space(); 40: 854: if node.negated do result.append("!"); 29: 855: result.appendN("in"); 29: 856: space(); 58: 857: if node.left do visitConcreteExpression(node.left); 29: 858: result.append(")"); 29: 859: closeParen(node); 29: 860: } -: 861: -: 862: @override function visitIndexExpression(IndexExpression* node) -: 863: { 328: 864: openParen(node); 656: 865: if node.expression do visitConcreteExpression(node.expression); 328: 866: result.append("["); 328: 867: foreach (const auto i; var auto e) in node.indexes do -: 868: { 332: 869: visitConcreteExpression(e); 336: 870: if i != node.indexes.length - 1 do result.appendN(", "); -: 871: } 328: 872: result.append("]"); 328: 873: closeParen(node); 328: 874: } -: 875: -: 876: @override function visitIntegerExpression(IntegerExpression* node) -: 877: { 7239: 878: openParen(node); 7239: 879: if !node.tok do -: 880: { -: 881: @noinit var s8[256] buff; 5642: 882: const usize len = snprintf(buff.ptr, buff.length, "%llu", node.value); 5642: 883: assert(len < 256); 5642: 884: result.appendN(buff[0 .. len]); -: 885: } 1597: 886: else do result.appendN(node.tok.text()[]); 7239: 887: closeParen(node); 7239: 888: } -: 889: -: 890: @override function visitLShiftAssignExpression(const LShiftAssignExpression* node) -: 891: { 1: 892: visitAssignExpression(node); 1: 893: } -: 894: -: 895: @override function visitLShiftExpression(const LShiftExpression* node) -: 896: { 3: 897: visitBinaryExpression(node); 3: 898: } -: 899: -: 900: @override function visitLabelDeclaration(const LabelDeclaration* node) -: 901: { 2: 902: indent(); 2: 903: result.appendN("label "); 2: 904: visitToken(node.name); 2: 905: } -: 906: -: 907: @override function visitLambdaExpression(LambdaExpression* node) -: 908: { 2: 909: openParen(node); 2: 910: result.appendN("function("); 2: 911: foreach (const auto i; var auto p) in node.func.parameters do -: 912: { 4: 913: visitVariableDeclaration(p); 4: 914: if i != node.func.parameters.length - 1 do 2: 915: result.appendN("; "); -: 916: } 2: 917: result.append(")"); 2: 918: if node.func.returnType && !isTypeVoid(node.func.returnType) do -: 919: { 2: 920: result.appendN(": "); 2: 921: visitConcreteType(node.func.returnType); -: 922: } 2: 923: result.appendN(" => "); 3: 924: if node.bodyAsExp do visitConcreteExpression(node.bodyAsExp); -: 925: else do -: 926: { 1: 927: visitStatement(node.func.body); 1: 928: result.shrink(); -: 929: } 2: 930: closeParen(node); 2: 931: } -: 932: -: 933: @override function visitLengthExpression(const LengthExpression* node) -: 934: { 349: 935: visitConcreteExpression(node.expression); 349: 936: result.appendN(".length"); 349: 937: } -: 938: -: 939: @override function visitSubAssignExpression(const SubAssignExpression* node) -: 940: { 1: 941: visitAssignExpression(node); 1: 942: } -: 943: -: 944: @override function visitSubExpression(const SubExpression* node) -: 945: { 109: 946: visitBinaryExpression(node); 109: 947: } -: 948: -: 949: @override function visitModAssignExpression(const ModAssignExpression* node) -: 950: { 1: 951: visitAssignExpression(node); 1: 952: } -: 953: -: 954: @override function visitModExpression(const ModExpression* node) -: 955: { 4: 956: visitBinaryExpression(node); 4: 957: } -: 958: -: 959: @override function visitMulAssignExpression(const MulAssignExpression* node) -: 960: { 4: 961: visitAssignExpression(node); 4: 962: } -: 963: -: 964: @override function visitMulExpression(const MulExpression* node) -: 965: { 17: 966: visitBinaryExpression(node); 17: 967: } -: 968: -: 969: @override function visitNegExpression(const NegExpression* node) -: 970: { 4: 971: visitPreExpression(node); 4: 972: } -: 973: -: 974: @override function visitNewExpression(NewExpression* node) -: 975: { 7: 976: openParen(node); 7: 977: result.appendN("new "); 7: 978: if node.allocator do -: 979: { 1: 980: result.append("("); 1: 981: visitConcreteExpression(node.expression); 1: 982: result.appendN(", "); 1: 983: visitConcreteExpression(node.allocator); 1: 984: result.append(")"); -: 985: } 6: 986: else do visitConcreteExpression(node.expression); 7: 987: closeParen(node); 7: 988: } -: 989: -: 990: @override function visitAstNode(AstNode* node) -: 991: { 56: 992: if var auto e = node:Expression* do visitConcreteExpression(e); 40: 993: else do if var auto d = node.asDeclaration() do visitConcreteDeclaration(d); 16: 994: else do if var auto s = node:Statement* do visitConcreteStatement(s); 24: 995: else do if var auto t = node.asType() do visitConcreteType(t); -: 996: else do assert(0, "not planned to be formatted"); 24: 997: } -: 998: -: 999: @override function visitNotExpression(const NotExpression* node) -:1000: { 94:1001: visitPreExpression(node); 94:1002: } -:1003: -:1004: @override function visitNullExpression(NullExpression* node) -:1005: { 42:1006: openParen(node); 42:1007: result.appendN("null"); 42:1008: closeParen(node); 42:1009: } -:1010: -:1011: @override function visitOnMatchStatement(OnMatchStatement* node) -:1012: { 7:1013: indent(); 7:1014: result.appendN("on "); 7:1015: foreach (const auto i; var auto e) in node.onMatchExpressions do -:1016: { 7:1017: visitConcreteExpression(e); 7:1018: if i != node.onMatchExpressions.length - 1 do result.appendN(", "); -:1019: } 7:1020: result.appendN(" do\n"); 7:1021: visitBlockStatement(node.blockStatement); 7:1022: } -:1023: -:1024: @override function visitOneCompExpression(const OneCompExpression* node) -:1025: { 6:1026: visitPreExpression(node); 6:1027: } -:1028: -:1029: @override function visitOptAccessExpression(OptAccessExpression* node) -:1030: { 32:1031: if var auto cmp = node.expression:CmpExpression* do 15:1032: visitConcreteExpression(cmp.left); 2:1033: else do if var auto ce = asCallExp(node.expression) do 0:1034: visitConcreteExpression(ce.expression); -:1035: else do 1:1036: visitConcreteExpression(node.expression); 16:1037: result.append("?"); 16:1038: } -:1039: -:1040: @override function visitOptAssignExpression(const OptAssignExpression* node) -:1041: { 3:1042: visitAssignExpression(node); 3:1043: } -:1044: -:1045: @override function visitOrAssignExpression(const OrAssignExpression* node) -:1046: { 1:1047: visitAssignExpression(node); 1:1048: } -:1049: -:1050: @override function visitOrExpression(const OrExpression* node) -:1051: { 2:1052: visitBinaryExpression(node); 2:1053: } -:1054: -:1055: @override function visitOrOrExpression(const OrOrExpression* node) -:1056: { 13:1057: visitBinaryExpression(node); 13:1058: } -:1059: -:1060: @override function visitOverloadDeclaration(OverloadDeclaration* node) -:1061: { 2:1062: result.appendN("overload "); 2:1063: visitToken(node.name); 2:1064: if noBody !in options do -:1065: { 1:1066: result.append("\n"); 1:1067: indent(); 1:1068: result.appendN("{\n"); 1:1069: growIndentLevel(); 1:1070: foreach (const auto i; var auto m) in node.members do -:1071: { 2:1072: indent(); 2:1073: visitConcreteExpression(m); 2:1074: result.appendN(i != node.members.length - 1 ? ",\n"[] else "\n"[]); -:1075: } 1:1076: shrinkIndentLevel(); 1:1077: indent(); 1:1078: result.append("}"); -:1079: } 2:1080: } -:1081: -:1082: @override function visitPostDecExpression(PostDecExpression* node) -:1083: { 3:1084: openParen(node); 3:1085: node.accept(this); 3:1086: result.appendN("--"); 3:1087: closeParen(node); 3:1088: } -:1089: -:1090: @override function visitPostIncExpression(PostIncExpression* node) -:1091: { 12:1092: openParen(node); 12:1093: node.accept(this); 12:1094: result.appendN("++"); 12:1095: closeParen(node); 12:1096: } -:1097: -:1098: function visitPreExpression(UnaryExpression* node) -:1099: { 287:1100: openParen(node); 287:1101: result.appendN(tokenString[node.operator]); 287:1102: node.accept(this); 287:1103: closeParen(node); 287:1104: } -:1105: -:1106: @override function visitPreDecExpression(const PreDecExpression* node) -:1107: { 2:1108: visitPreExpression(node); 2:1109: } -:1110: -:1111: @override function visitPreIncExpression(const PreIncExpression* node) -:1112: { 3:1113: visitPreExpression(node); 3:1114: } -:1115: -:1116: @override function visitProtectionDeclaration(ProtectionDeclaration* node) -:1117: { 1:1118: indent(); 1:1119: result.appendN("protection("); 1:1120: result.appendN(node.$protection.text()); 1:1121: result.append(")"); 1:1122: } -:1123: -:1124: @override function visitPtrExpression(const PtrExpression* node) -:1125: { 214:1126: visitConcreteExpression(node.expression); 214:1127: result.appendN(".ptr"); 214:1128: } -:1129: -:1130: @override function visitRShiftAssignExpression(const RShiftAssignExpression* node) -:1131: { 1:1132: visitAssignExpression(node); 1:1133: } -:1134: -:1135: @override function visitRShiftExpression(const RShiftExpression* node) -:1136: { 3:1137: visitBinaryExpression(node); 3:1138: } -:1139: -:1140: @override function visitRangeExpression(RangeExpression* node) -:1141: { 185:1142: openParen(node); 185:1143: visitConcreteExpression(node.left); 185:1144: result.appendN(" .. "); 185:1145: visitConcreteExpression(node.right); 185:1146: closeParen(node); 185:1147: } -:1148: -:1149: @override function visitRefCountExpression(RefCountExpression* node) -:1150: { 52:1151: visitConcreteExpression(node.expression); 52:1152: switch node.subOp do -:1153: { 47:1154: on RefCountOp.refcount_ do result.appendN(".refcount"); 2:1155: on RefCountOp.decref_ do result.appendN(".decref"); 2:1156: on RefCountOp.incref_ do result.appendN(".incref"); 1:1157: on RefCountOp.dup_ do result.appendN(".dup"); -:1158: } 52:1159: } -:1160: -:1161: @override function visitReturnStatement(ReturnStatement* node) -:1162: { 2:1163: indent(); 2:1164: result.appendN("return"); 2:1165: if node.expression do -:1166: { 2:1167: space(); 2:1168: visitConcreteExpression(node.expression); -:1169: } 2:1170: semicolon(); 2:1171: } -:1172: -:1173: @override function visitSetLengthExpression(SetLengthExpression* node) -:1174: { 6:1175: if node.expression do visitConcreteExpression(node.expression); 3:1176: result.appendN(".length = "); 6:1177: if node.newLength do visitConcreteExpression(node.newLength); 3:1178: } -:1179: -:1180: @override function visitSliceExpression(SliceExpression* node) -:1181: { 169:1182: openParen(node); 338:1183: if node.expression do visitConcreteExpression(node.expression); 169:1184: result.append("["); 337:1185: if node.range do visitRangeExpression(node.range); 1:1186: else do if node.tryAsTypeRca do result.append("+"); 169:1187: result.append("]"); 169:1188: if node.assignRhs do -:1189: { 1:1190: result.appendN(" = "); 1:1191: visitConcreteExpression(node.assignRhs); -:1192: } 169:1193: closeParen(node); 169:1194: } -:1195: -:1196: @override function visitStatement(Statement* node) -:1197: { 101:1198: visitConcreteStatement(node); 101:1199: switch node.kind do -:1200: { -:1201: on $assert, leftCurly, $break, $continue, 55:1202: semiColon, $goto, $return do newLine(); 46:1203: else do {} -:1204: } 101:1205: } -:1206: -:1207: @override function visitStringExpression(StringExpression* node) -:1208: { 176:1209: openParen(node); 176:1210: if node.value.type == stringLiteral do -:1211: { 148:1212: result.append(`"`); 148:1213: result.appendN(stringRepresentation(node.value)); 148:1214: result.append(`"`); -:1215: } -:1216: else do -:1217: { 28:1218: result.append("`"); 28:1219: result.appendN(node.value.text()); 28:1220: result.append("`"); -:1221: } 176:1222: closeParen(node); 176:1223: } -:1224: -:1225: @override function visitStructDeclaration(StructDeclaration* node) -:1226: { 32:1227: visitAggregateDeclaration(node, "struct"); 32:1228: } -:1229: -:1230: @override function visitSuperExpression(SuperExpression* node) -:1231: { 7:1232: openParen(node); 7:1233: result.appendN("super"); 7:1234: closeParen(node); 7:1235: } -:1236: -:1237: @override function visitSwitchStatement(SwitchStatement* node) -:1238: { 4:1239: indent(); 4:1240: result.appendN("switch "); 8:1241: if node.expression do visitConcreteExpression(node.expression); 4:1242: result.appendN(" do\n"); 4:1243: indent(); 4:1244: result.appendN("{\n"); 4:1245: foreach var auto om in node.onMatchStatements do 7:1246: visitOnMatchStatement(om); 4:1247: if node.elseBlock do -:1248: { 1:1249: indent(); 1:1250: result.appendN("else do\n"); 1:1251: visitBlockStatement(node.elseBlock); -:1252: } 4:1253: indent(); 4:1254: result.appendN("}\n"); 4:1255: } -:1256: -:1257: @override function visitThisExpression(ThisExpression* node) -:1258: { 10:1259: openParen(node); 10:1260: result.appendN("this"); 10:1261: closeParen(node); 10:1262: } -:1263: -:1264: function visitToken(Token* t) -:1265: { 1683:1266: if t.keywordAsIdentifier() do 1:1267: result.append("$"); 1683:1268: result.appendN(t.text()); 1683:1269: } -:1270: -:1271: @override function visitTupleExpression(TupleExpression* node) -:1272: { 19:1273: result.append("("); 19:1274: foreach (const auto i; var auto e) in node.expressions do -:1275: { 41:1276: visitConcreteExpression(e); 41:1277: if i != node.expressions.length - 1 do 22:1278: result.appendN(", "); -:1279: } 19:1280: result.append(")"); 19:1281: } -:1282: -:1283: @override function visitTypeAuto(const TypeAuto* node) -:1284: { 34:1285: result.appendN("auto"); 34:1286: } -:1287: -:1288: @override function visitTypeBool(const TypeBool* node) -:1289: { 117:1290: result.appendN("bool"); 117:1291: } -:1292: -:1293: @override function visitTypeClass(const TypeClass* node) -:1294: { 351:1295: addDeclarationName(node.declaration); 351:1296: } -:1297: -:1298: @override function visitTypeEcho(const TypeEcho* node) -:1299: { 1:1300: visitConcreteExpression(node.expression); 1:1301: } -:1302: -:1303: @override function visitTypeElements(TypeElements* node) -:1304: { 2:1305: visitConcreteType(node.elements); 2:1306: result.append("["); 2:1307: foreach (const auto i; var auto e) in node.indexes do -:1308: { 5:1309: visitConcreteExpression(e); 5:1310: if i != node.indexes.length - 1 do 3:1311: result.appendN(", "); -:1312: } 2:1313: result.append("]"); 2:1314: } -:1315: -:1316: @override function visitTypeEmptyArray(TypeEmptyArray* node) -:1317: { 3:1318: result.appendN("[]"); 3:1319: } -:1320: -:1321: @override function visitTypeEnum(const TypeEnum* node) -:1322: { 77:1323: visitToken(node.declaration.name); 77:1324: } -:1325: -:1326: @override function visitTypeEnumSet(const TypeEnumSet* node) -:1327: { 4:1328: result.appendN("bool["); 4:1329: visitToken(node.declaration.name); 4:1330: result.append("]"); 4:1331: } -:1332: -:1333: @override function visitTypeError(const TypeError* node) -:1334: { 118:1335: result.appendN(""); 118:1336: } -:1337: -:1338: @override function visitTypeExpression(TypeExpression* node) -:1339: { 708:1340: openParen(node); 1416:1341: if node.wrapped do visitConcreteType(node.wrapped); 708:1342: closeParen(node); 708:1343: } -:1344: -:1345: @override function visitTypeF32(const TypeF32* node) -:1346: { 83:1347: result.appendN("f32"); 83:1348: } -:1349: -:1350: @override function visitTypeF64(const TypeF64* node) -:1351: { 150:1352: result.appendN("f64"); 150:1353: } -:1354: -:1355: @override function visitTypeFunction(TypeFunction* node) -:1356: { 122:1357: const auto old = options; 122:1358: options += noBody; 244:1359: if node.declaration do visitConcreteDeclaration(node.declaration); 122:1360: options = old; 122:1361: } -:1362: -:1363: @override function visitTypeIdentifier(TypeIdentifier* node) -:1364: { 43014:1365: result.appendN(node.identifier.text()); 86028:1366: if const auto len = node.genericArguments.length do -:1367: { 1:1368: result.appendN(":["); 1:1369: foreach (const auto i; var auto a) in node.genericArguments.ptr[0 .. len] do -:1370: { 2:1371: visitConcreteExpression(a); 2:1372: if i != len - 1 do 1:1373: result.appendN(", "); -:1374: } 1:1375: result.append("]"); -:1376: } 43014:1377: if node.next do -:1378: { 25:1379: result.append("."); 25:1380: visitTypeIdentifier(node.next); -:1381: } 43014:1382: } -:1383: -:1384: @override function visitTypeNull(const TypeNull* node) -:1385: { 20:1386: result.appendN("null.typeof"); 20:1387: } -:1388: -:1389: @override function visitTypeOverload(const TypeOverload* node) -:1390: { 5:1391: visitToken(node.declaration.name); 5:1392: } -:1393: -:1394: @override function visitTypePointer(TypePointer* node) -:1395: { 118190:1396: if node.modified do visitConcreteType(node.modified); 59095:1397: result.append("*"); 59095:1398: } -:1399: -:1400: @override function visitTypeRange(const TypeRange* node) -:1401: { 19:1402: result.appendN("(range)"); 19:1403: } -:1404: -:1405: @override function visitTypeRcArray(TypeRcArray* node) -:1406: { 3428:1407: if node.modified do visitConcreteType(node.modified); 1714:1408: result.appendN("[+]"); 1714:1409: } -:1410: -:1411: @override function visitTypeS16(const TypeS16* node) -:1412: { 108:1413: result.appendN("s16"); 108:1414: } -:1415: -:1416: @override function visitTypeS32(const TypeS32* node) -:1417: { 288:1418: result.appendN("s32"); 288:1419: } -:1420: -:1421: @override function visitTypeS64(const TypeS64* node) -:1422: { 218:1423: result.appendN("s64"); 218:1424: } -:1425: -:1426: @override function visitTypeS8(const TypeS8* node) -:1427: { 5407:1428: result.appendN("s8"); 5407:1429: } -:1430: -:1431: @override function visitTypeSlice(TypeSlice* node) -:1432: { 4494:1433: if node.modified do visitConcreteType(node.modified); 2247:1434: result.appendN("[]"); 2247:1435: } -:1436: -:1437: @override function visitTypeStaticArray(TypeStaticArray* node) -:1438: { 8772:1439: if node.modified do visitConcreteType(node.modified); 4386:1440: result.append("["); 4386:1441: visitConcreteExpression(node.lengthExp); 4386:1442: result.append("]"); 4386:1443: } -:1444: -:1445: @override function visitTypeStruct(const TypeStruct* node) -:1446: { 561:1447: addDeclarationName(node.declaration); 561:1448: } -:1449: -:1450: @override function visitTypeTuple(TypeTuple* node) -:1451: { 49:1452: result.append("("); 49:1453: foreach (const auto i; var auto t) in node.types do -:1454: { 102:1455: visitConcreteType(t); 102:1456: if i != node.types.length - 1 do 56:1457: result.appendN(", "); -:1458: } 49:1459: result.append(")"); 49:1460: } -:1461: -:1462: @override function visitTypeU16(const TypeU16* node) -:1463: { 126:1464: result.appendN("u16"); 126:1465: } -:1466: -:1467: @override function visitTypeU32(const TypeU32* node) -:1468: { 829:1469: result.appendN("u32"); 829:1470: } -:1471: -:1472: @override function visitTypeU64(const TypeU64* node) -:1473: { 973:1474: result.appendN("u64"); 973:1475: } -:1476: -:1477: @override function visitTypeU8(const TypeU8* node) -:1478: { 9421:1479: result.appendN("u8"); 9421:1480: } -:1481: -:1482: @override function visitTypeUnambiguous(TypeUnambiguous* node) -:1483: { 1:1484: result.append("("); 2:1485: if node.unambiguous do visitConcreteType(node.unambiguous); 1:1486: result.append(")"); 1:1487: } -:1488: -:1489: @override function visitTypeUnion(const TypeUnion* node) -:1490: { 3:1491: addDeclarationName(node.declaration); 3:1492: } -:1493: -:1494: @override function visitTypeVoid(const TypeVoid* node) -:1495: { 68:1496: result.appendN("void"); 68:1497: } -:1498: -:1499: @override function visitUnionDeclaration(const UnionDeclaration* node) -:1500: { 5:1501: visitAggregateDeclaration(node, "union"); 5:1502: } -:1503: -:1504: @override function visitUnitDeclaration(UnitDeclaration* node) -:1505: { 112:1506: if node.attributes do visitAttributes(node.attributes); 112:1507: result.appendN("unit "); 224:1508: if node.identifiers do visitConcreteType(node.identifiers); 112:1509: if noBody !in options do -:1510: { 112:1511: semicolonAndNewLine(); 112:1512: node.accept(this); -:1513: } 112:1514: } -:1515: -:1516: @override function visitVariableDeclaration(VariableDeclaration* node) -:1517: { 355:1518: if node.attributes do visitAttributes(node.attributes); 349:1519: result.appendN(storageClassesText(node.stc)); 698:1520: if node.type do visitConcreteType(node.type); 349:1521: if node.name do -:1522: { 349:1523: space(); 349:1524: visitToken(node.name); -:1525: } 349:1526: if node.initializer do -:1527: { 35:1528: result.appendN(" = "); 35:1529: visitConcreteExpression(node.initializer); -:1530: } 349:1531: } -:1532: -:1533: @override function visitVersionBlockDeclaration(VersionBlockDeclaration* node) -:1534: { 7:1535: indent(); 7:1536: result.appendN("version "); 7:1537: visitConcreteExpression(node.versionExpression); 7:1538: result.appendN(" do\n"); 7:1539: indent(); 7:1540: result.appendN("{\n"); 7:1541: growIndentLevel(); 14:1542: if node.thenDeclarations do visitDeclarations(node.thenDeclarations); 7:1543: shrinkIndentLevel(); 7:1544: indent(); 7:1545: result.append("}"); 7:1546: if node.elseDeclarations do -:1547: { 4:1548: newLine(); 4:1549: indent(); 4:1550: result.appendN("else do\n"); 4:1551: indent(); 4:1552: result.appendN("{\n"); 4:1553: growIndentLevel(); 4:1554: visitDeclarations(node.elseDeclarations); 4:1555: shrinkIndentLevel(); 4:1556: indent(); 4:1557: result.append("}"); -:1558: } 7:1559: } -:1560: -:1561: @override function visitVersionBlockStatement(VersionBlockStatement* node) -:1562: { 1:1563: indent(); 1:1564: result.appendN("version "); 1:1565: visitExpression(node.versionExpression); 1:1566: result.appendN(" do\n"); 2:1567: if node.thenBlock do visitBlockStatement(node.thenBlock); 1:1568: if node.elseBlock do -:1569: { 1:1570: indent(); 1:1571: result.appendN("else do\n"); 1:1572: visitBlockStatement(node.elseBlock); -:1573: } 1:1574: } -:1575: -:1576: @override function visitVersionIdentExpression(VersionIdentExpression* node) -:1577: { 11:1578: openParen(node); 11:1579: result.appendN(node.identifier.text()); 11:1580: closeParen(node); 11:1581: } -:1582: -:1583: @override function visitWhileStatement(WhileStatement* node) -:1584: { 2:1585: indent(); 2:1586: result.appendN("while "); 4:1587: if node.condition do visitConcreteExpression(node.condition); 2:1588: result.appendN(" do\n"); 2:1589: visitBlockStatement(node.blockStatement); 2:1590: } -:1591: -:1592: @override function visitWithStatement(WithStatement* node) -:1593: { 2:1594: indent(); 2:1595: result.appendN("with ("); 2:1596: foreach (const auto i; var auto t) in node.expressions do -:1597: { 3:1598: visitConcreteExpression(t); 4:1599: if i != node.expressions.length - 1 do result.appendN(", "); -:1600: } 2:1601: result.appendN(") do\n"); 2:1602: visitBlockStatement(node.blockStatement); 2:1603: } -:1604: -:1605: @override function visitXorAssignExpression(const XorAssignExpression* node) -:1606: { 1:1607: visitAssignExpression(node); 1:1608: } -:1609: -:1610: @override function visitXorExpression(const XorExpression* node) -:1611: { 2:1612: visitBinaryExpression(node); 2:1613: } -:1614:} -:1615: -:1616:function assertFormatedAs(s8[] source; s8[] expected; u64 line) -:1617:{ -:1618: import styx.lexer, styx.parser, styx.session, styx.position; -:1619: 112:1620: var Lexer* lex = (new Lexer).createFromText(source, echo(filename), line:u32); 112:1621: var Parser* prs = (new Parser).create(lex); 112:1622: var UnitDeclaration* u = prs.parseUnitDeclaration(); 112:1623: assert(u, "the input code is invalid"); -:1624: 112:1625: var s8[+] result = u.format(testMode); 112:1626: if result[0 .. expected.length] != expected do -:1627: { 0:1628: printf("expected:\n---\n%s\n---\n", (expected ~ "\0").ptr); 0:1629: printf("actual:\n---\n%s\n---\n", (result ~ "\0").ptr); 0:1630: session.error(echo(filename), (line:u32, 0), "the formatted code does not match expectations"); 0:1631: system.fflush(0); 0:1632: asm ("ud2"); -:1633: } -:1634: 112:1635: delete prs; 112:1636: delete lex; 112:1637:} -:1638: -:1639:@unittest function test1() -:1640:{ -:1641: var s8[] c = "unit a /**/ . /**/ b ; function main ( ) : s32;"; -:1642: var s8[] e = -:1643:"unit a.b; -:1644:function main():s32;"; -:1645: c.assertFormatedAs(e, echo(line)); -:1646:} -:1647: -:1648:@unittest function test2() -:1649:{ -:1650: var s8[] c = "unit a; import a,b in c;"; -:1651: var s8[] e = -:1652:"unit a; -:1653:import a, b in c;"; -:1654: c.assertFormatedAs(e, echo(line)); -:1655:} -:1656: -:1657:@unittest function test4() -:1658:{ -:1659: var s8[] c = "unit a; class A:B,c.D {}"; -:1660: var s8[] e= -:1661:"unit a; -:1662:class A: B, c.D -:1663:{ -:1664:}"; -:1665: c.assertFormatedAs(e, echo(line)); -:1666:} -:1667: -:1668:@unittest function test5() -:1669:{ -:1670: var s8[] c = "unit a; struct A {}"; -:1671: var s8[] e= -:1672:"unit a; -:1673:struct A -:1674:{ -:1675:}"; -:1676: c.assertFormatedAs(e, echo(line)); -:1677:} -:1678: -:1679:@unittest function test6() -:1680:{ -:1681: var s8[] c = "unit a; union A {}"; -:1682: var s8[] e= -:1683:"unit a; -:1684:union A -:1685:{ -:1686:}"; -:1687: c.assertFormatedAs(e, echo(line)); -:1688:} -:1689: -:1690:@unittest function test10() -:1691:{ -:1692: var s8[] c = "unit a; class A {}"; -:1693: var s8[] e= -:1694:"unit a; -:1695:class A -:1696:{ -:1697:}"; -:1698: c.assertFormatedAs(e, echo(line)); -:1699:} -:1700: -:1701:@unittest function test11() -:1702:{ -:1703: var s8[] c = "unit a; enum A:s8 {a=0,b=1}"; -:1704: var s8[] e= -:1705:"unit a; -:1706:enum A: s8 -:1707:{ -:1708: a = 0, -:1709: b = 1 -:1710:}"; -:1711: c.assertFormatedAs(e, echo(line)); -:1712:} -:1713: -:1714:@unittest function test12() -:1715:{ -:1716: var s8[] c = "unit a; function foo();"; -:1717: var s8[] e= -:1718:"unit a; -:1719:function foo();"; -:1720: c.assertFormatedAs(e, echo(line)); -:1721:} -:1722: -:1723:@unittest function test15() -:1724:{ -:1725: var s8[] c = "unit a; function foo(){-- a ++ ;}"; -:1726: var s8[] e= -:1727:"unit a; -:1728:function foo() -:1729:{ -:1730: --a++; -:1731:}"; -:1732: c.assertFormatedAs(e, echo(line)); -:1733:} -:1734: -:1735:@unittest function test16() -:1736:{ -:1737: var s8[] c = "unit a; function foo(){a = b*c+d;}"; -:1738: var s8[] e= -:1739:"unit a; -:1740:function foo() -:1741:{ -:1742: a = ((b * c) + d); -:1743:}"; -:1744: c.assertFormatedAs(e, echo(line)); -:1745:} -:1746: -:1747:@unittest function test17() -:1748:{ -:1749: var s8[] c = "unit a; function foo(){a = b*c+8+d[e]+f[0..2]*g./* c */h;}"; -:1750: var s8[] e= -:1751:"unit a; -:1752:function foo() -:1753:{ -:1754: a = ((b * c) + (8 + (d[e] + (f[0 .. 2] * g.h)))); -:1755:}"; -:1756: c.assertFormatedAs(e, echo(line)); -:1757:} -:1758: -:1759:@unittest function test18() -:1760:{ -:1761: var s8[] c = "unit a; function foo(){a = [0,1] + (a[1]); }"; -:1762: var s8[] e= -:1763:"unit a; -:1764:function foo() -:1765:{ -:1766: a = ([0, 1] + (a[1])); -:1767:}"; -:1768: c.assertFormatedAs(e, echo(line)); -:1769:} -:1770: -:1771:@unittest function test19() -:1772:{ -:1773: var s8[] c = "unit a; function foo(){a = b * c + d; }"; -:1774: var s8[] e= -:1775:"unit a; -:1776:function foo() -:1777:{ -:1778: a = ((b * c) + d); -:1779:}"; -:1780: c.assertFormatedAs(e, echo(line)); -:1781:} -:1782: -:1783:@unittest function test20() -:1784:{ -:1785: var s8[] c = "unit a; function foo(){a = b + c * d - 8; }"; -:1786: var s8[] e= -:1787:"unit a; -:1788:function foo() -:1789:{ -:1790: a = ((b + (c * d)) - 8); -:1791:}"; -:1792: c.assertFormatedAs(e, echo(line)); -:1793:} -:1794: -:1795:@unittest function test21() -:1796:{ -:1797: var s8[] c = "unit a; function foo(){a = b in c + 8; }"; -:1798: var s8[] e= -:1799:"unit a; -:1800:function foo() -:1801:{ -:1802: a = (b in (c + 8)); -:1803:}"; -:1804: c.assertFormatedAs(e, echo(line)); -:1805:} -:1806: -:1807:@unittest function test22() -:1808:{ -:1809: var s8[] c = "unit a; function foo(){call(p0,p1 );}"; -:1810: var s8[] e= -:1811:"unit a; -:1812:function foo() -:1813:{ -:1814: call(p0, p1); -:1815:}"; -:1816: c.assertFormatedAs(e, echo(line)); -:1817:} -:1818: -:1819:@unittest function test23() -:1820:{ -:1821: var s8[] c = "unit a; function foo(): s8 {return 0: s8;}"; -:1822: var s8[] e= -:1823:"unit a; -:1824:function foo():s8 -:1825:{ -:1826: return 0:s8; -:1827:}"; -:1828: c.assertFormatedAs(e, echo(line)); -:1829:} -:1830: -:1831:@unittest function test24() -:1832:{ -:1833: var s8[] c = "unit a; function foo(){if (a)do {a++;} else do {a--;}}"; -:1834: var s8[] e= -:1835:"unit a; -:1836:function foo() -:1837:{ -:1838: if (a) do -:1839: { -:1840: a++; -:1841: } -:1842: else do -:1843: { -:1844: a--; -:1845: } -:1846:}"; -:1847: c.assertFormatedAs(e, echo(line)); -:1848:} -:1849: -:1850:@unittest function test25() -:1851:{ -:1852: var s8[] c = "unit a; function foo(){if (a) do a++; else do a--;}"; -:1853: var s8[] e= -:1854:"unit a; -:1855:function foo() -:1856:{ -:1857: if (a) do -:1858: a++; -:1859: else do -:1860: a--; -:1861:}"; -:1862: c.assertFormatedAs(e, echo(line)); -:1863:} -:1864: -:1865:@unittest function test26() -:1866:{ -:1867: var s8[] c = "unit a; function foo(){if (a && a || a << 1 && a >> 1 % 0) do {} }"; -:1868: var s8[] e= -:1869:"unit a; -:1870:function foo() -:1871:{ -:1872: if (((a && a) || ((a << 1) && (a >> (1 % 0))))) do -:1873: { -:1874: } -:1875:}"; -:1876: c.assertFormatedAs(e, echo(line)); -:1877:} -:1878: -:1879:@unittest function test27() -:1880:{ -:1881: var s8[] c = "unit a; function foo(){ a = b ~ c ^ d | r; }"; -:1882: var s8[] e= -:1883:"unit a; -:1884:function foo() -:1885:{ -:1886: a = (((b ~ c) ^ d) | r); -:1887:}"; -:1888: c.assertFormatedAs(e, echo(line)); -:1889:} -:1890: -:1891:@unittest function test28() -:1892:{ -:1893: var s8[] c = "unit a; function foo(){if(const auto a = call()) do {a++;}}"; -:1894: var s8[] e= -:1895:"unit a; -:1896:function foo() -:1897:{ -:1898: if (const auto a = call()) do -:1899: { -:1900: a++; -:1901: } -:1902:}"; -:1903: c.assertFormatedAs(e, echo(line)); -:1904:} -:1905: -:1906:@unittest function test29() -:1907:{ -:1908: var s8[] c = "unit a; function foo(){if(var auto a = call()) do {a++;}}"; -:1909: var s8[] e= -:1910:"unit a; -:1911:function foo() -:1912:{ -:1913: if (var auto a = call()) do -:1914: { -:1915: a++; -:1916: } -:1917:}"; -:1918: c.assertFormatedAs(e, echo(line)); -:1919:} -:1920: -:1921:@unittest function test30() -:1922:{ -:1923: var s8[] c = "unit a; function foo(){while(true)do{a++;}}"; -:1924: var s8[] e= -:1925:"unit a; -:1926:function foo() -:1927:{ -:1928: while (true) do -:1929: { -:1930: a++; -:1931: } -:1932:}"; -:1933: c.assertFormatedAs(e, echo(line)); -:1934:} -:1935: -:1936:@unittest function test31() -:1937:{ -:1938: var s8[] c = "unit a; function foo(){while(true)do a++;}"; -:1939: var s8[] e= -:1940:"unit a; -:1941:function foo() -:1942:{ -:1943: while (true) do -:1944: a++; -:1945:}"; -:1946: c.assertFormatedAs(e, echo(line)); -:1947:} -:1948: -:1949:@unittest function test32() -:1950:{ -:1951: var s8[] c = "unit a; function foo(){foreach(const auto i) in I do {if (0) do -:1952: {break @here , afterCall();}}}"; -:1953: var s8[] e= -:1954:"unit a; -:1955:function foo() -:1956:{ -:1957: foreach (const auto i) in I do -:1958: { -:1959: if (0) do -:1960: { -:1961: break @here, afterCall(); -:1962: } -:1963: } -:1964:}"; -:1965: c.assertFormatedAs(e, echo(line)); -:1966:} -:1967: -:1968:@unittest function test33() -:1969:{ -:1970: var s8[] c = "unit a; function foo(){ label L0; -:1971: if (rand(12) == 0)do -:1972: { -:1973: goto @L0, afterThat; -:1974: } -:1975:}"; -:1976: var s8[] e= -:1977:"unit a; -:1978:function foo() -:1979:{ -:1980: label L0; -:1981: if ((rand(12) == 0)) do -:1982: { -:1983: goto @L0, afterThat; -:1984: } -:1985:}"; -:1986: c.assertFormatedAs(e, echo(line)); -:1987:} -:1988: -:1989:@unittest function test34() -:1990:{ -:1991: var s8[] c = "unit a; function foo(){foreach(const auto i; var auto b) in I do {if (0) -:1992: do {break @here ,afterCall();}}}"; -:1993: var s8[] e= -:1994:"unit a; -:1995:function foo() -:1996:{ -:1997: foreach (const auto i; var auto b) in I do -:1998: { -:1999: if (0) do -:2000: { -:2001: break @here, afterCall(); -:2002: } -:2003: } -:2004:}"; -:2005: c.assertFormatedAs(e, echo(line)); -:2006:} -:2007: -:2008:@unittest function test35() -:2009:{ -:2010: var s8[] c = "unit a; function foo(){foreach const auto i in I do if (0) do break @ here , afterCall();}"; -:2011: var s8[] e= -:2012:"unit a; -:2013:function foo() -:2014:{ -:2015: foreach const auto i in I do -:2016: if (0) do -:2017: break @here, afterCall(); -:2018:}"; -:2019: c.assertFormatedAs(e, echo(line)); -:2020:} -:2021: -:2022:@unittest function test36() -:2023:{ -:2024: var s8[] c = "unit a; function foo(){foreach(const auto i) in I do if (0) do continue @ here, afterCall();}"; -:2025: var s8[] e= -:2026:"unit a; -:2027:function foo() -:2028:{ -:2029: foreach (const auto i) in I do -:2030: if (0) do -:2031: continue @here, afterCall(); -:2032:}"; -:2033: c.assertFormatedAs(e, echo(line)); -:2034:} -:2035: -:2036:@unittest function test37() -:2037:{ -:2038: var s8[] c = "unit a; function foo(){foreach(const auto i) in 0 .. 1 do{ callThat();}}"; -:2039: var s8[] e= -:2040:"unit a; -:2041:function foo() -:2042:{ -:2043: foreach (const auto i) in 0 .. 1 do -:2044: { -:2045: callThat(); -:2046: } -:2047:}"; -:2048: c.assertFormatedAs(e, echo(line)); -:2049:} -:2050: -:2051:@unittest function test38() -:2052:{ -:2053: var s8[] c = "unit a; function foo(){foreach(const auto i) in I do {if (0)do -:2054: {continue afterCall();} andDontDoThis();}}"; -:2055: var s8[] e= -:2056:"unit a; -:2057:function foo() -:2058:{ -:2059: foreach (const auto i) in I do -:2060: { -:2061: if (0) do -:2062: { -:2063: continue afterCall(); -:2064: } -:2065: andDontDoThis(); -:2066: } -:2067:}"; -:2068: c.assertFormatedAs(e, echo(line)); -:2069:} -:2070: -:2071:@unittest function test39() -:2072:{ -:2073: var s8[] c = "unit a; @@A@@B function foo(const s32 a): s64;"; -:2074: var s8[] e= -:2075:"unit a; -:2076:@@A @@B function foo(const s32 a):s64; -:2077:"; -:2078: c.assertFormatedAs(e, echo(line)); -:2079:} -:2080: -:2081:@unittest function test40() -:2082:{ -:2083: var s8[] c = "unit a; function foo(): A.B[8][]*;"; -:2084: var s8[] e= -:2085:"unit a; -:2086:function foo():A.B[8][]*; -:2087:"; -:2088: c.assertFormatedAs(e, echo(line)); -:2089:} -:2090: -:2091:@unittest function test41() -:2092:{ -:2093: var s8[] c = "unit a; static function foo(const s32 a; var s32 b);"; -:2094: var s8[] e= -:2095:"unit a; -:2096:static function foo(const s32 a; var s32 b); -:2097:"; -:2098: c.assertFormatedAs(e, echo(line)); -:2099:} -:2100: -:2101:@unittest function test42() -:2102:{ -:2103: var s8[] c = "unit a; alias funcPtr = static function _ (const s32 a): s64[ ] ;"; -:2104: var s8[] e= -:2105:"unit a; -:2106:alias funcPtr = static function _(const s32 a):s64[]; -:2107:"; -:2108: c.assertFormatedAs(e, echo(line)); -:2109:} -:2110: -:2111:@unittest function test43() -:2112:{ -:2113: var s8[] c = "unit a; alias funcPtr = static function _ (const s32 a; var s8 b);"; -:2114: var s8[] e= -:2115:"unit a; -:2116:alias funcPtr = static function _(const s32 a; var s8 b); -:2117:"; -:2118: c.assertFormatedAs(e, echo(line)); -:2119:} -:2120: -:2121:@unittest function test44() -:2122:{ -:2123: var s8[] c = "unit a; alias funcPtr = function _ (const s32 a): s64[ ];"; -:2124: var s8[] e= -:2125:"unit a; -:2126:alias funcPtr = function _(const s32 a):s64[]; -:2127:"; -:2128: c.assertFormatedAs(e, echo(line)); -:2129:} -:2130: -:2131:@unittest function test45() -:2132:{ -:2133: var s8[] c = "unit a; alias FuncT = function _():(function _() : s8*)[] ;"; -:2134: var s8[] e= -:2135:"unit a; -:2136:alias FuncT = function _():(function _():s8*)[]; -:2137:"; -:2138: c.assertFormatedAs(e, echo(line)); -:2139:} -:2140: -:2141:@unittest function test46() -:2142:{ -:2143: var s8[] c = "unit a; alias FuncT = function() : T [ ] ;"; -:2144: var s8[] e= -:2145:"unit a; -:2146:alias FuncT = function ():T[]; -:2147:"; -:2148: c.assertFormatedAs(e, echo(line)); -:2149:} -:2150: -:2151:@unittest function test47() -:2152:{ -:2153: var s8[] c = "unit a; const s8[2] a = [0:s8,1:s8];"; -:2154: var s8[] e= -:2155:"unit a; -:2156:const s8[2] a = [0:s8, 1:s8]; -:2157:"; -:2158: c.assertFormatedAs(e, echo(line)); -:2159:} -:2160: -:2161:@unittest function test48() -:2162:{ -:2163: var s8[] c = "unit a; var s8*** a; var s8*** b ; var s8* ** c;"; -:2164: var s8[] e= -:2165:"unit a; -:2166:var s8*** a; -:2167:var s8*** b; -:2168:var s8*** c; -:2169:"; -:2170: c.assertFormatedAs(e, echo(line)); -:2171:} -:2172: -:2173:@unittest function test49() -:2174:{ -:2175: var s8[] c = "unit a; class A {static const s8 a;}"; -:2176: var s8[] e= -:2177:"unit a; -:2178:class A -:2179:{ -:2180: const static s8 a; -:2181:} -:2182:"; -:2183: c.assertFormatedAs(e, echo(line)); -:2184:} -:2185: -:2186:@unittest function test50() -:2187:{ -:2188: var s8[] c = "unit a; class A {static const s8 a;static const s8 b;}"; -:2189: var s8[] e= -:2190:"unit a; -:2191:class A -:2192:{ -:2193: const static s8 a; -:2194: const static s8 b; -:2195:} -:2196:"; -:2197: c.assertFormatedAs(e, echo(line)); -:2198:} -:2199: -:2200:@unittest function test51() -:2201:{ -:2202: var s8[] c = "unit a; version a do{const s8 b;}else do{const s8 c;}"; -:2203: var s8[] e= -:2204:"unit a; -:2205:version a do -:2206:{ -:2207: const s8 b; -:2208:} -:2209:else do -:2210:{ -:2211: const s8 c; -:2212:} -:2213:"; -:2214: c.assertFormatedAs(e, echo(line)); -:2215:} -:2216: -:2217:@unittest function test52() -:2218:{ -:2219: var s8[] c = "unit importer;version(none)do{import importable.x;}"; -:2220: var s8[] e= -:2221:"unit importer; -:2222:version (none) do -:2223:{ -:2224: import importable.x; -:2225:} -:2226:"; -:2227: c.assertFormatedAs(e, echo(line)); -:2228:} -:2229: -:2230:@unittest function test53() -:2231:{ -:2232: var s8[] c = "unit a; version(! a)do{}"; -:2233: var s8[] e= -:2234:"unit a; -:2235:version (!a) do -:2236:{ -:2237:} -:2238:"; -:2239: c.assertFormatedAs(e, echo(line)); -:2240:} -:2241: -:2242:@unittest function test54() -:2243:{ -:2244: var s8[] c = "unit a; version !(a) do{}"; -:2245: var s8[] e= -:2246:"unit a; -:2247:version !(a) do -:2248:{ -:2249:} -:2250:"; -:2251: c.assertFormatedAs(e, echo(line)); -:2252:} -:2253: -:2254:@unittest function test55() -:2255:{ -:2256: var s8[] c = "unit a; version(a && b)do{const s8 b;}else do{const s8 c;}"; -:2257: var s8[] e= -:2258:"unit a; -:2259:version ((a && b)) do -:2260:{ -:2261: const s8 b; -:2262:} -:2263:else do -:2264:{ -:2265: const s8 c; -:2266:} -:2267:"; -:2268: c.assertFormatedAs(e, echo(line)); -:2269:} -:2270: -:2271:@unittest function test56() -:2272:{ -:2273: var s8[] c = "unit a; version((a && b))do{const s8 b;}else do{const s8 c;}"; -:2274: var s8[] e= -:2275:"unit a; -:2276:version (((a && b))) do -:2277:{ -:2278: const s8 b; -:2279:} -:2280:else do -:2281:{ -:2282: const s8 c; -:2283:} -:2284:"; -:2285: c.assertFormatedAs(e, echo(line)); -:2286:} -:2287: -:2288:@unittest function test57() -:2289:{ -:2290: var s8[] c = "unit a; version( a || b) do {const s8 b;}else do {const s8 c;}"; -:2291: var s8[] e= -:2292:"unit a; -:2293:version ((a || b)) do -:2294:{ -:2295: const s8 b; -:2296:} -:2297:else do -:2298:{ -:2299: const s8 c; -:2300:} -:2301:"; -:2302: c.assertFormatedAs(e, echo(line)); -:2303:} -:2304: -:2305:version noen do @unittest function test58() -:2306:{ -:2307: var s8[] c = "unit a; function foo(){version(a) do {const s8 b;}else do{const s8 c;}}"; -:2308: var s8[] e= -:2309:"unit a; -:2310:function foo() -:2311:{ -:2312: version (a) do -:2313: { -:2314: const s8 b; -:2315: } -:2316: else do -:2317: { -:2318: const s8 c; -:2319: } -:2320:} -:2321:"; -:2322: c.assertFormatedAs(e, echo(line)); -:2323:} -:2324: -:2325:@unittest function test59() -:2326:{ -:2327: var s8[] c = "unit a; import system,classes,io.streams; import other;"; -:2328: var s8[] e= -:2329:"unit a; -:2330:import system, classes, io.streams; -:2331:import other; -:2332:"; -:2333: c.assertFormatedAs(e, echo(line)); -:2334:} -:2335: -:2336:@unittest function test60() -:2337:{ -:2338: var s8[] c = "unit a; protection(strict)"; -:2339: var s8[] e= -:2340:"unit a; -:2341:protection(strict)"; -:2342: c.assertFormatedAs(e, echo(line)); -:2343:} -:2344: -:2345:@unittest function test61() -:2346:{ -:2347: var s8[] c ="unit a;function foo(){ -:2348: switch e do -:2349: { -:2350: on 0 do That(); -:2351: on 1 do This(); -:2352: else do ThisAndThat(); -:2353: } -:2354:}"; -:2355: var s8[] e= -:2356:"unit a; -:2357:function foo() -:2358:{ -:2359: switch e do -:2360: { -:2361: on 0 do -:2362: That(); -:2363: on 1 do -:2364: This(); -:2365: else do -:2366: ThisAndThat(); -:2367: } -:2368:} -:2369:"; -:2370: c.assertFormatedAs(e, echo(line)); -:2371:} -:2372: -:2373:@unittest function test64() -:2374:{ -:2375: var s8[] c = "unit a; function foo(){assert(true & true);}"; -:2376: var s8[] e= -:2377:"unit a; -:2378:function foo() -:2379:{ -:2380: assert((true & true)); -:2381:}"; -:2382: c.assertFormatedAs(e, echo(line)); -:2383:} -:2384: -:2385:@unittest function test65() -:2386:{ -:2387: var s8[] c = "unit a; function foo(){label L0 ; }"; -:2388: var s8[] e= -:2389:"unit a; -:2390:function foo() -:2391:{ -:2392: label L0; -:2393:}"; -:2394: c.assertFormatedAs(e, echo(line)); -:2395:} -:2396: -:2397:@unittest function test66() -:2398:{ -:2399: var s8[] c = "unit a; @@a function foo() {@@b@@c const auto d = 0;}"; -:2400: var s8[] e= -:2401:"unit a; -:2402:@@a function foo() -:2403:{ -:2404: @@b @@c const auto d = 0; -:2405:}"; -:2406: c.assertFormatedAs(e, echo(line)); -:2407:} -:2408: -:2409:@unittest function test67() -:2410:{ -:2411: var s8[] c = "unit a; @@foo struct Foo{@@bar class Bar{@@baz static class Baz{}}}"; -:2412: var s8[] e= -:2413:"unit a; -:2414:@@foo struct Foo -:2415:{ -:2416: @@bar class Bar -:2417: { -:2418: @@baz static class Baz -:2419: { -:2420: } -:2421: } -:2422:}"; -:2423: c.assertFormatedAs(e, echo(line)); -:2424:} -:2425: -:2426:@unittest function test70() -:2427:{ -:2428: var s8[] c = "unit a; function foo(){ if (a + b > c + d)do{} }"; -:2429: var s8[] e= -:2430:"unit a; -:2431:function foo() -:2432:{ -:2433: if (((a + b) > (c + d))) do -:2434: { -:2435: } -:2436:}"; -:2437: c.assertFormatedAs(e, echo(line)); -:2438:} -:2439: -:2440:@unittest function test71() -:2441:{ -:2442: var s8[] c = "unit a; function foo(){ if (a && b > c)do{} }"; -:2443: var s8[] e= -:2444:"unit a; -:2445:function foo() -:2446:{ -:2447: if ((a && (b > c))) do -:2448: { -:2449: } -:2450:}"; -:2451: c.assertFormatedAs(e, echo(line)); -:2452:} -:2453: -:2454:@unittest function test72() -:2455:{ -:2456: var s8[] c = "unit a; function foo(){const bool b = echo(compiles, a + 8);}"; -:2457: var s8[] e= -:2458:"unit a; -:2459:function foo() -:2460:{ -:2461: const bool b = echo(compiles, (a + 8)); -:2462:}"; -:2463: c.assertFormatedAs(e, echo(line)); -:2464:} -:2465: -:2466:@unittest function test73() -:2467:{ -:2468: var s8[] c = "unit a; function foo(){const bool b = echo(isType, T, s8[]);}"; -:2469: var s8[] e= -:2470:"unit a; -:2471:function foo() -:2472:{ -:2473: const bool b = echo(isType, T, s8[]); -:2474:}"; -:2475: c.assertFormatedAs(e, echo(line)); -:2476:} -:2477: -:2478:@unittest function test74() -:2479:{ -:2480: var s8[] c = "unit a; function foo(){const bool b = echo(is, T, T);}"; -:2481: var s8[] e= -:2482:"unit a; -:2483:function foo() -:2484:{ -:2485: const bool b = echo(is, T, T); -:2486:}"; -:2487: c.assertFormatedAs(e, echo(line)); -:2488:} -:2489: -:2490:@unittest function test76() -:2491:{ -:2492: var s8[] c = "unit a; @ @ metadata (13,42) function foo();"; -:2493: var s8[] e= -:2494:"unit a; -:2495:@@metadata(13, 42) function foo(); -:2496:"; -:2497: c.assertFormatedAs(e, echo(line)); -:2498:} -:2499: -:2500:@unittest function test77() -:2501:{ -:2502: var s8[] c = "unit a; function foo(@@a @ @b @@c f32 p; s32 r);"; -:2503: var s8[] e= -:2504:"unit a; -:2505:function foo(@@a @@b @@c f32 p; s32 r);"; -:2506: c.assertFormatedAs(e, echo(line)); -:2507:} -:2508: -:2509:@unittest function test78() -:2510:{ -:2511: var s8[] c = "unit a; function foo(){ const bool b = a ! /*C*/ /*D*/ in b & c; }"; -:2512: var s8[] e= -:2513:"unit a; -:2514:function foo() -:2515:{ -:2516: const bool b = (a !in (b & c)); -:2517:}"; -:2518: c.assertFormatedAs(e, echo(line)); -:2519:} -:2520: -:2521:@unittest function test79() -:2522:{ -:2523: var s8[] c = "unit a; function foo(){ const auto b = a[0..1]; }"; -:2524: var s8[] e= -:2525:"unit a; -:2526:function foo() -:2527:{ -:2528: const auto b = a[0 .. 1]; -:2529:}"; -:2530: c.assertFormatedAs(e, echo(line)); -:2531:} -:2532: -:2533:@unittest function test80() -:2534:{ -:2535: var s8[] c = "unit a; function foo(){ const bool b =false; }"; -:2536: var s8[] e= -:2537:"unit a; -:2538:function foo() -:2539:{ -:2540: const bool b = false; -:2541:}"; -:2542: c.assertFormatedAs(e, echo(line)); -:2543:} -:2544: -:2545:@unittest function test81() -:2546:{ -:2547: var s8[] c = "unit a; function foo(){ const f32 b =0.5; }"; -:2548: var s8[] e= -:2549:"unit a; -:2550:function foo() -:2551:{ -:2552: const f32 b = 0.5; -:2553:}"; -:2554: c.assertFormatedAs(e, echo(line)); -:2555:} -:2556: -:2557:@unittest function test82() -:2558:{ -:2559: var s8[] c = `unit a; function foo(){ const auto b = "0.5"; }`; -:2560: var s8[] e= -:2561:`unit a; -:2562:function foo() -:2563:{ -:2564: const auto b = "0.5"; -:2565:}`; -:2566: c.assertFormatedAs(e, echo(line)); -:2567:} -:2568: -:2569:@unittest function test83() -:2570:{ -:2571: var s8[] c = `unit a; function foo(){ with(a) do {b();} }`; -:2572: var s8[] e= -:2573:`unit a; -:2574:function foo() -:2575:{ -:2576: with (a) do -:2577: { -:2578: b(); -:2579: } -:2580:}`; -:2581: c.assertFormatedAs(e, echo(line)); -:2582:} -:2583: -:2584:@unittest function test84() -:2585:{ -:2586: var s8[] c = `unit a; function foo(){ foreach (const auto a ) in b do c(); d(); }`; -:2587: var s8[] e= -:2588:`unit a; -:2589:function foo() -:2590:{ -:2591: foreach (const auto a) in b do -:2592: c(); -:2593: d(); -:2594:}`; -:2595: c.assertFormatedAs(e, echo(line)); -:2596:} -:2597: -:2598:@unittest function test85() -:2599:{ -:2600: var s8[] c = `unit a; function foo(){ with (a, b[0]) do c(); d(); }`; -:2601: var s8[] e= -:2602:`unit a; -:2603:function foo() -:2604:{ -:2605: with (a, b[0]) do -:2606: c(); -:2607: d(); -:2608:}`; -:2609: c.assertFormatedAs(e, echo(line)); -:2610:} -:2611: -:2612:@unittest function test86() -:2613:{ -:2614: var s8[] c = `unit a; function foo(){ super(); this.a = 0; this; super; }`; -:2615: var s8[] e= -:2616:`unit a; -:2617:function foo() -:2618:{ -:2619: super(); -:2620: this.a = 0; -:2621: this; -:2622: super; -:2623:}`; -:2624: c.assertFormatedAs(e, echo(line)); -:2625:} -:2626: -:2627:@unittest function test87() -:2628:{ -:2629: var s8[] c = `unit a; struct Foo; union Bar;`; -:2630: var s8[] e= -:2631:`unit a; -:2632:struct Foo; -:2633:union Bar;`; -:2634: c.assertFormatedAs(e, echo(line)); -:2635:} -:2636: -:2637:@unittest function test88() -:2638:{ -:2639: var s8[] c = `unit a; function foo(): s8* {return null;}`; -:2640: var s8[] e= -:2641:`unit a; -:2642:function foo():s8* -:2643:{ -:2644: return null; -:2645:}`; -:2646: c.assertFormatedAs(e, echo(line)); -:2647:} -:2648: -:2649:@unittest function test89() -:2650:{ -:2651: var s8[] c = `unit a; function foo() {assert(s32.size);}`; -:2652: var s8[] e= -:2653:`unit a; -:2654:function foo() -:2655:{ -:2656: assert(s32.size); -:2657:}`; -:2658: c.assertFormatedAs(e, echo(line)); -:2659:} -:2660: -:2661:@unittest function test90() -:2662:{ -:2663: var s8[] c = `unit a; function foo(... );`; -:2664: var s8[] e= -:2665:`unit a; -:2666:function foo(...);`; -:2667: c.assertFormatedAs(e, echo(line)); -:2668:} -:2669: -:2670:@unittest function test91() -:2671:{ -:2672: var s8[] c = `unit a; function foo(){ const auto a = 1 / 2; }`; -:2673: var s8[] e= -:2674:`unit a; -:2675:function foo() -:2676:{ -:2677: const auto a = (1 / 2); -:2678:}`; -:2679: c.assertFormatedAs(e, echo(line)); -:2680:} -:2681: -:2682:@unittest function test92() -:2683:{ -:2684: var s8[] c = `unit a; function foo(){ const auto c = echo(is, s32, s32); }`; -:2685: var s8[] e= -:2686:`unit a; -:2687:function foo() -:2688:{ -:2689: const auto c = echo(is, s32, s32); -:2690:}`; -:2691: c.assertFormatedAs(e, echo(line)); -:2692:} -:2693: -:2694:@unittest function test93() -:2695:{ -:2696: var s8[] c = `unit a; overload s { s1 , s2 }`; -:2697: var s8[] e= -:2698:`unit a; -:2699:overload s -:2700:{ -:2701: s1, -:2702: s2 -:2703:}`; -:2704: c.assertFormatedAs(e, echo(line)); -:2705:} -:2706: -:2707:@unittest function test94() -:2708:{ -:2709: var s8[] c = `unit a; function foo(){ const auto a = b ? c else d ; }`; -:2710: var s8[] e= -:2711:`unit a; -:2712:function foo() -:2713:{ -:2714: const auto a = b ? c else d; -:2715:}`; -:2716: c.assertFormatedAs(e, echo(line)); -:2717:} -:2718: -:2719:@unittest function test95() -:2720:{ -:2721: var s8[] c = `unit a; function foo(){ switch a do { on 1 do {continue on 2;} on 2 do {} } }`; -:2722: var s8[] e= -:2723:`unit a; -:2724:function foo() -:2725:{ -:2726: switch a do -:2727: { -:2728: on 1 do -:2729: { -:2730: continue on 2; -:2731: } -:2732: on 2 do -:2733: { -:2734: } -:2735: } -:2736:}`; -:2737: c.assertFormatedAs(e, echo(line)); -:2738:} -:2739: -:2740:@unittest function test96() -:2741:{ -:2742: var s8[] c = `unit a; function foo(){ switch a do { on 1 do {break on;} on 2 do {} } }`; -:2743: var s8[] e= -:2744:`unit a; -:2745:function foo() -:2746:{ -:2747: switch a do -:2748: { -:2749: on 1 do -:2750: { -:2751: break on; -:2752: } -:2753: on 2 do -:2754: { -:2755: } -:2756: } -:2757:}`; -:2758: c.assertFormatedAs(e, echo(line)); -:2759:} -:2760: -:2761:@unittest function test96_2() -:2762:{ -:2763: var s8[] c = `unit a; function foo(){ switch a do { on 1 do { continue on else ;} } }`; -:2764: var s8[] e= -:2765:`unit a; -:2766:function foo() -:2767:{ -:2768: switch a do -:2769: { -:2770: on 1 do -:2771: { -:2772: continue on else; -:2773: } -:2774: } -:2775:}`; -:2776: c.assertFormatedAs(e, echo(line)); -:2777:} -:2778: -:2779:@unittest function test97() -:2780:{ -:2781: var s8[] c = `unit a; function foo(){ asm("code","constr",a,0):T;}`; -:2782: var s8[] e = -:2783:`unit a; -:2784:function foo() -:2785:{ -:2786: asm("code", "constr", a, 0): T; -:2787:}`; -:2788: c.assertFormatedAs(e, echo(line)); -:2789:} -:2790: -:2791:@unittest function test98() -:2792:{ -:2793: var s8[] c = `unit a; var auto a = function(s32 a; s32 b): bool => false;`; -:2794: var s8[] e = -:2795:`unit a; -:2796:var auto a = function(s32 a; s32 b): bool => false;`; -:2797: c.assertFormatedAs(e, echo(line)); -:2798:} -:2799: -:2800:@unittest function test99() -:2801:{ -:2802: var s8[] c = `unit a; var auto a = function(s32 a; s32 b): bool => {false;};`; -:2803: var s8[] e = -:2804:`unit a; -:2805:var auto a = function(s32 a; s32 b): bool => { -:2806: false; -:2807:} -:2808:;`; -:2809: c.assertFormatedAs(e, echo(line)); -:2810:} -:2811: -:2812:@unittest function test100() -:2813:{ -:2814: var s8[] c = `unit a; var auto a = b[1,2,3];`; -:2815: var s8[] e = -:2816:`unit a; -:2817:var auto a = b[1, 2, 3];`; -:2818: c.assertFormatedAs(e, echo(line)); -:2819:} -:2820: -:2821:@unittest function test101() -:2822:{ -:2823: var s8[] c = `unit a; var auto a = b*=b/=b%=b<<=b>>=b+=b-=b~=b&=b|=b^=b;`; -:2824: var s8[] e = -:2825:`unit a; -:2826:var auto a = b *= b /= b %= b <<= b >>= b += b -= b ~= b &= b |= b ^= b;`; -:2827: c.assertFormatedAs(e, echo(line)); -:2828:} -:2829: -:2830:@unittest function test102() -:2831:{ -:2832: var s8[] c = "unit a; var auto a = `\\r\\n`;"; -:2833: var s8[] e = -:2834:"unit a; -:2835:var auto a = `\\r\\n`;"; -:2836: c.assertFormatedAs(e, echo(line)); -:2837:} -:2838: -:2839:@unittest function test103() -:2840:{ -:2841: var s8[] c = `unit a; var auto a = "\r\n\\\"";`; -:2842: var s8[] e = -:2843:`unit a; -:2844:var auto a = "\x0D\x0A\\\"";`; -:2845: c.assertFormatedAs(e, echo(line)); -:2846:} -:2847: -:2848:@unittest function test104() -:2849:{ -:2850: var s8[] c = `unit a; @inline enum MAX_PATH : s32 = 255;`; -:2851: var s8[] e = -:2852:`unit a; -:2853:@inline enum MAX_PATH: s32 = 255;`; -:2854: c.assertFormatedAs(e, echo(line)); -:2855:} -:2856: -:2857:@unittest function test105() -:2858:{ -:2859: var s8[] c = `unit a; @inline import a;`; -:2860: var s8[] e = -:2861:`unit a; -:2862:@inline import a;`; -:2863: c.assertFormatedAs(e, echo(line)); -:2864:} -:2865: -:2866:@unittest function test106() -:2867:{ -:2868: var s8[] c = `unit a; var auto a = a?.b;`; -:2869: var s8[] e = -:2870:`unit a; -:2871:var auto a = a?.b;`; -:2872: c.assertFormatedAs(e, echo(line)); -:2873:} -:2874: -:2875:@unittest function test108() -:2876:{ -:2877: var s8[] c = `unit a; function f(){ *~-!&a+$; ++a.decref; a.incref; a.refcount; a.dup; a ?= b; -:2878: (f64).min;version a do { } -:2879: else do {} }`; -:2880: var s8[] e = -:2881:`unit a; -:2882:function f() -:2883:{ -:2884: (*~-!&a + $); -:2885: ++a.decref; -:2886: a.incref; -:2887: a.refcount; -:2888: a.dup; -:2889: a ?= b; -:2890: (f64).min; -:2891: version a do -:2892: { -:2893: } -:2894: else do -:2895: { -:2896: } -:2897:}`; -:2898: c.assertFormatedAs(e, echo(line)); -:2899:} -:2900: -:2901:@unittest function testNewDelete1() -:2902:{ -:2903: var s8[] c = `unit a; var auto a = new(C,allocator);`; -:2904: var s8[] e = -:2905:`unit a; -:2906:var auto a = new (C, allocator);`; -:2907: c.assertFormatedAs(e, echo(line)); -:2908:} -:2909: -:2910:@unittest function testNewDelete2() -:2911:{ -:2912: var s8[] c = `unit a; var auto a = new C;`; -:2913: var s8[] e = -:2914:`unit a; -:2915:var auto a = new C;`; -:2916: c.assertFormatedAs(e, echo(line)); -:2917:} -:2918: -:2919:@unittest function testNewDelete3() -:2920:{ -:2921: var s8[] c = `unit a; function f(){delete(a,allocator);}`; -:2922: var s8[] e = -:2923:`unit a; -:2924:function f() -:2925:{ -:2926: delete (a, allocator); -:2927:}`; -:2928: c.assertFormatedAs(e, echo(line)); -:2929:} -:2930: -:2931:@unittest function testNewDelete4() -:2932:{ -:2933: var s8[] c = `unit a; function f(){ delete a ;}`; -:2934: var s8[] e = -:2935:`unit a; -:2936:function f() -:2937:{ -:2938: delete a; -:2939:}`; -:2940: c.assertFormatedAs(e, echo(line)); -:2941:} -:2942: -:2943:@unittest function testDollarKw() -:2944:{ -:2945: var s8[] c = `unit a; function f(S* this; S* $if){ $if = null ; this = null ; }`; -:2946: var s8[] e = -:2947:`unit a; -:2948:function f(S* this; S* $if) -:2949:{ -:2950: $if = null; -:2951: this = null; -:2952:}`; -:2953: c.assertFormatedAs(e, echo(line)); -:2954:} -:2955: -:2956:@unittest function testTuples() -:2957:{ -:2958: var s8[] c = `unit a; var ( s32, s32, s32 )[0 , 1] a = (0,0);`; -:2959: var s8[] e = -:2960:`unit a; -:2961:var (s32, s32, s32)[0, 1] a = (0, 0);`; -:2962: c.assertFormatedAs(e, echo(line)); -:2963:} -:2964: -:2965:@unittest function testAsmBody() -:2966:{ -:2967: var s8[] c = `unit a; function f() = asm "ret";`; -:2968: var s8[] e = -:2969:`unit a; -:2970:function f() = asm -:2971:"ret" -:2972:;`; -:2973: c.assertFormatedAs(e, echo(line)); -:2974:} -:2975: -:2976:@unittest function testApply() -:2977:{ -:2978: var s8[] c = `unit a; var auto b = apply(generic,e1, e2);`; -:2979: var s8[] e = -:2980:`unit a; -:2981:var auto b = apply(generic, e1, e2);`; -:2982: c.assertFormatedAs(e, echo(line)); -:2983:} -:2984: -:2985:@unittest function testApplyPostStyle() -:2986:{ -:2987: var s8[] c = `unit a; var auto b = generic:[e1, e2];`; -:2988: var s8[] e = -:2989:`unit a; -:2990:var auto b = generic:[e1, e2];`; -:2991: c.assertFormatedAs(e, echo(line)); -:2992:} -:2993: -:2994:@unittest function testGenericParams() -:2995:{ -:2996: var s8[] c = `unit a; struct S[T,U]{}`; -:2997: var s8[] e = -:2998:`unit a; -:2999:struct S[T, U] -:3000:{ -:3001:}`; -:3002: c.assertFormatedAs(e, echo(line)); -:3003:} -:3004: -:3005:@unittest function testTypeIdentGenericArgs() -:3006:{ -:3007: var s8[] c = `unit a; var S:[a,b] sab ;`; -:3008: var s8[] e = -:3009:`unit a; -:3010:var S:[a, b] sab;`; -:3011: c.assertFormatedAs(e, echo(line)); -:3012:} -:3013: -:3014:@unittest function coverAliasExp() -:3015:{ -:3016: var s8[] c = `unit a; alias a = apply(A,1) ;`; -:3017: var s8[] e = -:3018:`unit a; -:3019:alias a = apply(A, 1);`; -:3020: c.assertFormatedAs(e, echo(line)); -:3021:} -:3022: -:3023:@unittest function coverTypeEchoExp() -:3024:{ -:3025: var s8[] c = `unit a; alias T = echo(type, 0 + 0) ;`; -:3026: var s8[] e = -:3027:`unit a; -:3028:alias T = echo(type, (0 + 0));`; -:3029: c.assertFormatedAs(e, echo(line)); -:3030:} -:3031: -:3032:@unittest function testGenericParamType() -:3033:{ -:3034: var s8[] c = `unit a; struct S[ u64 T ]{}`; -:3035: var s8[] e = -:3036:`unit a; -:3037:struct S[u64 T] -:3038:{ -:3039:}`; -:3040: c.assertFormatedAs(e, echo(line)); -:3041:} -:3042: -:3043:@unittest function testAliasExp() -:3044:{ -:3045: var s8[] c = `unit a; alias a => b ;`; -:3046: var s8[] e = -:3047:`unit a; -:3048:alias a => b; -:3049:`; -:3050: c.assertFormatedAs(e, echo(line)); -:3051:} -:3052: -:3053:@unittest function testExternalMemberFunc() -:3054:{ -:3055: var s8[] c = `unit a; function A.b();`; -:3056: var s8[] e = -:3057:`unit a; -:3058:function A.b(); -:3059:`; -:3060: c.assertFormatedAs(e, echo(line)); -:3061:} <<<<<< EOF # path=src/styx/ast/statements.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/ast/statements.sx -: 1:unit styx.ast.statements; -: 2: -: 3:@private import -: 4: styx.position, -: 5: styx.ast.base, -: 6: styx.ast.declarations, -: 7: styx.ast.visitor, -: 8: styx.token, -: 9: styx.string_switch, -: 10: ; -: 11: -: 12:/// Returns: a `SwitchStatement*` if the argument is one else `null` -: 13:function asBlockStatement(Statement* node): BlockStatement* -: 14:{ 4539: 15: return node.kind == leftCurly ? *((&node):BlockStatement**) else null; -: 16:} -: 17: -: 18:/// Returns: a `ExpressionStatement*` if the argument is one else `null` -: 19:function asExpressionStatement(Statement* node): ExpressionStatement* -: 20:{ 9: 21: return node.kind == semiColon ? *((&node):ExpressionStatement**) else null; -: 22:} -: 23: -: 24:/// Returns: a `SwitchStatement*` if the argument is one else `null` -: 25:function asIfElseStatement(Statement* node): IfElseStatement* -: 26:{ 23655: 27: return node.kind == $if ? *((&node):IfElseStatement**) else null; -: 28:} -: 29: -: 30:/// Returns: a `SwitchStatement*` if the argument is one else `null` -: 31:function asDeclarationStatement(Statement* node): DeclarationStatement* -: 32:{ 29706: 33: return node.kind == eopDecl ? *((&node):DeclarationStatement**) else null; -: 34:} -: 35: -: 36:/// AssertStatement -: 37:@final class AssertStatement: Statement -: 38:{ -: 39: @@Semantic var bool isStatic; -: 40: /// The expression to verify. -: 41: var Expression* expression; -: 42: /// The optional message. -: 43: var Expression* message; -: 44: /// A backup of the non-optimized expression. -: 45: var Expression* unoptimized; -: 46: /// -: 47: @constructor function create(var Position startPos) -: 48: { 2413: 49: this.kind = $assert; 2413: 50: this.startPos = startPos; 2413: 51: } -: 52: /// -: 53: @override function free() -: 54: { 81: 55: if unoptimized != expression && unoptimized do unoptimized.free(); 81: 56: expression?.free(); 81: 57: message?.free(); 81: 58: super(); 81: 59: } -: 60: /// -: 61: @override function accept(AstVisitor* visitor) -: 62: { 10880: 63: if expression do visitor.visitExpression(expression); 7138: 64: if message do visitor.visitExpression(message); 5440: 65: } -: 66:} -: 67: -: 68:/// BlockStatement -: 69:@final class BlockStatement : Statement -: 70:{ -: 71: /// -: 72: var bool noScope; -: 73: /// -: 74: var bool isSingle; -: 75: /// Ending position -: 76: var Position stopPos; -: 77: /// Declarations or statement located in the block. -: 78: var Statement*[+] statements; -: 79: /// -: 80: @@Semantic var VariableDeclaration*[+] managedLocals; -: 81: /// -: 82: @constructor function create(var Position startPos) -: 83: { 15306: 84: this.kind = leftCurly; 15306: 85: this.startPos = startPos; 15306: 86: } -: 87: /// -: 88: @override function free() -: 89: { 1359: 90: foreach var auto s in statements do 2677: 91: s.free(); 1359: 92: statements.decref; 1359: 93: managedLocals.decref; 1359: 94: super(); 1359: 95: } -: 96: /// -: 97: @override function accept(AstVisitor* visitor) -: 98: { 45290: 99: foreach var auto s in statements do 112439:100: visitor.visitStatement(s); 45290:101: } -:102:} -:103: -:104:/// BreakOnStatement -:105:@final class BreakOnStatement : FlowControl -:106:{ -:107: @constructor function create(var Position startPos) -:108: { 12:109: this.startPos = startPos; 12:110: this.kind = skBreakOn; 12:111: this.flow = Flow.create(FlowKind.isBreakOn); 12:112: } 24:113: @override function accept(AstVisitor* visitor) {} -:114:} -:115: -:116:/// BreakStatement -:117:@final class BreakStatement : LabeledFlowControl -:118:{ -:119: /// -:120: @constructor function create(var Position startPos) -:121: { 723:122: this.startPos = startPos; 723:123: this.kind = $break; 723:124: this.flow = Flow.create(FlowKind.isBreak); 723:125: } -:126:} -:127: -:128:/// -:129:@final class ContinueOnStatement : FlowControl -:130:{ -:131: /// -:132: @@Semantic var bool isElseTargeted; -:133: /// -:134: var Expression* targetMatch; -:135: /// -:136: @@Semantic var OnMatchStatement* realTarget; -:137: /// -:138: @constructor function create(var Position startPos) -:139: { 37:140: this.startPos = startPos; 37:141: this.kind = skContinueOn; 37:142: this.flow = Flow.create(FlowKind.isContinueOn); 37:143: } -:144: /// -:145: @override function free() -:146: { 11:147: targetMatch?.free(); 11:148: super(); 11:149: } -:150: /// -:151: @override function accept(AstVisitor* visitor) -:152: { 113:153: if targetMatch do visitor.visitExpression(targetMatch); 79:154: } -:155:} -:156: -:157:/// ContinueStatement -:158:@final class ContinueStatement : LabeledFlowControl -:159:{ -:160: /// -:161: @constructor function create(var Position startPos) -:162: { 269:163: this.startPos = startPos; 269:164: this.kind = $continue; 269:165: this.flow = Flow.create(FlowKind.isContinue); 269:166: } -:167:} -:168: -:169:/// DeclarationStatement -:170:@final class DeclarationStatement : Statement -:171:{ -:172: /// -:173: var Declaration* declaration; -:174: /// -:175: @constructor function create(var Position startPos; Declaration* declaration = null) -:176: { 7311:177: this.kind = eopDecl; 7311:178: this.startPos = startPos; 7311:179: this.declaration = declaration; 7311:180: this.flow = Flow.create(FlowKind.isNext); 7311:181: } -:182: /// -:183: @override function free() -:184: { 252:185: declaration.free(); 252:186: super(); 252:187: } -:188: /// -:189: @override function accept(AstVisitor* visitor) -:190: { 58772:191: if declaration do visitor.visitDeclaration(declaration); 29386:192: } -:193:} -:194: -:195:/// ExpressionStatement -:196:@final class ExpressionStatement : Statement -:197:{ -:198: /// The expression. -:199: var Expression* expression; -:200: /// -:201: @constructor function create(var Position startPos; Expression* expression) -:202: { 13689:203: this.startPos = startPos; 13689:204: this.kind = semiColon; 13689:205: this.flow = Flow.create(FlowKind.isNext); 13689:206: this.expression = expression; 13689:207: } -:208: /// -:209: @override function free() -:210: { 1328:211: expression?.free(); 1328:212: super(); 1328:213: } -:214: /// -:215: @override function accept(AstVisitor* visitor) -:216: { 69170:217: if expression do visitor.visitExpression(expression); 34585:218: } -:219:} -:220: -:221:/// Ancestor for BreakStatement, ContinueStatement and ReturnStatement -:222:class FlowControl: Statement -:223:{ -:224: /// position past the expression -:225: var Position stopPos; -:226: /// The expression that gives the return or that is executed before the break/continue -:227: var Expression* expression; -:228: /// The list locals that are declared in the matching foreach/while -:229: @@Semantic var VariableDeclaration*[+] managedLocals; -:230: /// The node that gives the thing being controled -:231: @@Semantic var AstNode* target; -:232: /// -:233: @override function free() -:234: { 520:235: managedLocals.decref; 520:236: expression?.free(); 520:237: super(); 520:238: } -:239: /// -:240: @override function accept(AstVisitor* visitor) -:241: { 28134:242: if expression do visitor.visitExpression(expression); 16988:243: } -:244:} -:245: -:246:/// ForeachStatement -:247:@final class ForeachStatement : Statement -:248:{ -:249: /// If the variable list is between parens -:250: @@Semantic var bool hasParens; -:251: /// Set if trying foreach based on @operator(a[n]) -:252: @@Semantic var bool skipBlockSema; -:253: /// -:254: @@Semantic var bool isReversed; -:255: /// The variables. -:256: var VariableDeclaration*[+] variables; -:257: /// The expression that give the enumerable. -:258: var Expression* expression; -:259: /// The single statement or block. -:260: var BlockStatement* blockStatement; -:261: /// -:262: @constructor function create(var Position startPos) -:263: { 688:264: this.kind = $foreach; 688:265: this.startPos = startPos; 688:266: } -:267: /// -:268: @override function free() -:269: { 43:270: foreach var VariableDeclaration* vd in variables do 39:271: vd.free(); 43:272: variables.decref; 43:273: expression?.free(); 43:274: blockStatement?.free(); 43:275: super(); 43:276: } -:277: /// -:278: @override function accept(AstVisitor* visitor) -:279: { 1940:280: foreach var VariableDeclaration* vd in variables do 2680:281: visitor.visitDeclaration(vd); 3880:282: if expression do visitor.visitExpression(expression); 3880:283: if blockStatement do visitor.visitStatement(blockStatement); 1940:284: } -:285:} -:286: -:287:/// GotoStatement -:288:@final class GotoStatement : LabeledFlowControl -:289:{ -:290: /// -:291: @constructor function create(var Position startPos) -:292: { 16:293: this.kind = $goto; 16:294: this.flow = Flow.create(FlowKind.isGoto); 16:295: this.startPos = startPos; 16:296: } -:297:} -:298: -:299:enum ConditionValue : s8 -:300:{ -:301: undef , -:302: $false, -:303: $true, -:304:} -:305: -:306:/// IfElseStatement -:307:@final class IfElseStatement : Statement -:308:{ -:309: /// If the ifVariable is between parens -:310: var bool hasParens; -:311: /// -:312: var ConditionValue conditionValue; -:313: /// The condition when it's an expression. -:314: var Expression* condition; -:315: /// The condition when it's a new scoped variable. -:316: var VariableDeclaration* ifVariable; -:317: /// The single statement or block when condition is true. -:318: var BlockStatement* thenBlock; -:319: /// The single statement or block when condition is false. -:320: var BlockStatement* elseBlock; -:321: /// -:322: @constructor function create(var Position startPos) -:323: { 5601:324: this.kind = $if; 5601:325: this.startPos = startPos; 5601:326: } -:327: /// -:328: @override function free() -:329: { 489:330: condition?.free(); 489:331: ifVariable?.free(); 489:332: thenBlock?.free(); 489:333: elseBlock?.free(); 489:334: super(); 489:335: } -:336: /// -:337: @override function accept(AstVisitor* visitor) -:338: { 29063:339: if condition do visitor.visitExpression(condition); 794:340: else do if ifVariable do visitor.visitDeclaration(ifVariable); 29460:341: if thenBlock do visitor.visitStatement(thenBlock); 16824:342: if elseBlock do visitor.visitStatement(elseBlock); 14730:343: } -:344:} -:345: -:346:/// Ancestor for GotoStatement and derived of FlowControl -:347:class LabeledFlowControl: FlowControl -:348:{ -:349: /// The token that indicates the label to go to. -:350: var Token* $label; -:351:} -:352: -:353:/// OnMatchStatement -:354:@final class OnMatchStatement : AstNode -:355:{ -:356: @@Semantic var Flow flow; -:357: /// The expressions that match. -:358: var Expression*[+] onMatchExpressions; -:359: /// Single Statement or block. -:360: var BlockStatement* blockStatement; -:361: /// -:362: @constructor function create(var Position startPos) -:363: { 1711:364: this.startPos = startPos; 1711:365: } -:366: /// -:367: @override function free() -:368: { 152:369: foreach var Expression* e in onMatchExpressions do 171:370: e.free(); 152:371: onMatchExpressions.decref; 152:372: blockStatement?.free(); 152:373: super(); 152:374: } -:375: /// -:376: @override function accept(AstVisitor* visitor) -:377: { 4663:378: foreach var Expression* e in onMatchExpressions do 5252:379: visitor.visitExpression(e); 9326:380: if blockStatement do visitor.visitStatement(blockStatement); 4663:381: } -:382:} -:383: -:384:/// ReturnStatement -:385:@final class ReturnStatement : FlowControl -:386:{ -:387: /// if returning an @return variable of type TypeRcArray -:388: @@Semantic var bool skipRcaProtection; -:389: /// if returning by reference -:390: @@Semantic var bool isVar; -:391: /// -:392: @constructor function create(var Position startPos; Expression* expression = null) -:393: { 6803:394: this.kind = $return; 6803:395: this.flow = Flow.create(FlowKind.isReturn); 6803:396: this.startPos = startPos; 6803:397: this.expression = expression; 6803:398: } -:399:} -:400: -:401:/// SwitchStatement -:402:@final class SwitchStatement : Statement -:403:{ -:404: /// to supress effect of --check=switches -:405: @@Semantic var bool fullCov; -:406: /// The expression to match. -:407: var Expression* expression; -:408: /// The matches. -:409: var OnMatchStatement*[+] onMatchStatements; -:410: /// The fallback for unmatched cases. -:411: var BlockStatement* elseBlock; -:412: /// Data used to turn switch over string a switch over integer literals -:413: var StringSwitchData* ssd; -:414: /// -:415: @@Semantic var ContinueOnStatement*[+] continueOns; -:416: /// -:417: @@Semantic var BreakOnStatement*[+] breakOns; -:418: /// -:419: @constructor function create(var Position startPos) -:420: { 349:421: this.kind = $switch; 349:422: this.startPos = startPos; 349:423: } -:424: /// -:425: @override function free() -:426: { 53:427: expression?.free(); 53:428: foreach var auto om in onMatchStatements do 143:429: om.free(); 53:430: onMatchStatements.decref; 53:431: breakOns.decref; 53:432: elseBlock?.free(); 53:433: if ssd do delete ssd; 53:434: super(); 53:435: } -:436: /// -:437: @override function accept(AstVisitor* visitor) -:438: { 1760:439: if expression do visitor.visitExpression(expression); 880:440: foreach var auto om in onMatchStatements do 4663:441: visitor.visitOnMatchStatement(om); 1626:442: if elseBlock do visitor.visitStatement(elseBlock); 880:443: } -:444:} -:445: -:446:/// VersionBlockStatement -:447:@final class VersionBlockStatement : Statement -:448:{ -:449: /// Indicates which declarations or statements are valid. -:450: @@Semantic var bool isTrue; -:451: /// Expressions allowing to select the true or false declarations or statements. -:452: var Expression* versionExpression; -:453: /// The declarations or statements when the versionExpression is verified. -:454: var BlockStatement* thenBlock; -:455: /// The declarations or statements when the versionExpression is not verified. -:456: var BlockStatement* elseBlock; -:457: /// -:458: @constructor function create(var Position startPos) -:459: { 58:460: this.kind = $version; 58:461: this.startPos = startPos; 58:462: } -:463: /// -:464: @override function free() -:465: { 30:466: versionExpression?.free(); 30:467: thenBlock?.free(); 30:468: elseBlock?.free(); 30:469: super(); 30:470: } -:471: /// -:472: @override function accept(AstVisitor* visitor) -:473: { 126:474: if versionExpression do visitor.visitExpression(versionExpression); 113:475: if thenBlock do visitor.visitStatement(thenBlock); 72:476: if elseBlock do visitor.visitStatement(elseBlock); 63:477: } -:478:} -:479: -:480:/// WhileStatement -:481:@final class WhileStatement : Statement -:482:{ -:483: /// The condition -:484: var Expression* condition; -:485: /// The single statement or block. -:486: var BlockStatement* blockStatement; -:487: /// -:488: @constructor function create(var Position startPos) -:489: { 519:490: this.kind = $while; 519:491: this.startPos = startPos; 519:492: } -:493: /// -:494: @override function free() -:495: { 46:496: condition?.free(); 46:497: blockStatement?.free(); 46:498: super(); 46:499: } -:500: /// -:501: @override function accept(AstVisitor* visitor) -:502: { 2806:503: if condition do visitor.visitExpression(condition); 2806:504: if blockStatement do visitor.visitStatement(blockStatement); 1403:505: } -:506:} -:507: -:508:/// WithStatement -:509:@final class WithStatement: Statement -:510:{ -:511: /// to execute DeclExp only once -:512: @@Semantic var Expression*[+] preExpressions; -:513: /// The expressions giving scopes to try in the nested block -:514: var Expression*[+] expressions; -:515: /// The block statement -:516: var BlockStatement* blockStatement; -:517: /// -:518: @constructor function create(var Position startPos) -:519: { 38:520: this.kind = $with; 38:521: this.startPos = startPos; 38:522: } -:523: /// -:524: @override function free() -:525: { 14:526: foreach var auto e in expressions do 19:527: e.free(); 14:528: expressions.decref; 14:529: preExpressions.decref; 14:530: blockStatement?.free(); 14:531: super(); 14:532: } -:533: /// -:534: @override function accept(AstVisitor* visitor) -:535: { 48:536: foreach var auto e in expressions do 50:537: visitor.visitExpression(e); 96:538: if blockStatement do visitor.visitStatement(blockStatement); 48:539: } -:540:} <<<<<< EOF # path=src/styx/ast/types.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/ast/types.sx -: 1:unit styx.ast.types; -: 2: -: 3:@private import -: 4: styx.ast.base, -: 5: styx.ast.visitor, -: 6: styx.ast.declarations, -: 7: styx.ast.expressions, -: 8: styx.token, -: 9: styx.session, -: 10: styx.symbol, -: 11: ; -: 12: -: 13:/// Returns: a TypeAggregate if `t.resolved()` is one else `null` -: 14:function asTypeAggregate(Type* t): TypeAggregate* -: 15:{ 204134: 16: t = t.resolved(); 204134: 17: switch t.kind do -: 18: { 95613: 19: on $class, $struct, $union do return *((&t):TypeAggregate**); 108521: 20: else do return null; -: 21: } -: 22:} -: 23: -: 24:/// Returns: if `t` is `TypeAuto` -: 25:function isTypeAuto(Type* t): bool -: 26:{ 94218: 27: return t.kind == TokenType.$auto; -: 28:} -: 29: -: 30:/// Returns: if `t` is `TypeBool` -: 31:function isTypeBool(Type* t): bool -: 32:{ 42677: 33: return t.kind == TokenType.$bool; -: 34:} -: 35: -: 36:/// Returns: a TypeClass if `t.resolved()` is one else `null` -: 37:function asTypeClass(Type* t): TypeClass* -: 38:{ 207169: 39: t = t.resolved(); 207169: 40: return t.kind == $class ? *((&t):TypeClass**) else null; -: 41:} -: 42: -: 43:/// Returns: a TypeEnum if `t.resolved()` is one else `null` -: 44:function asTypeEnum(Type* t): TypeEnum* -: 45:{ 56286: 46: t = t.resolved(); 56286: 47: return t.kind == $enum ? *((&t):TypeEnum**) else null; -: 48:} -: 49: -: 50:/// Returns: a TypeEnumSet if `t.resolved()` is one else `null` -: 51:function asTypeEnumSet(Type* t): TypeEnumSet* -: 52:{ 91225: 53: t = t.resolved(); 91225: 54: return t.kind == tkEnumSet ? *((&t):TypeEnumSet**) else null; -: 55:} -: 56: -: 57:/// Returns: if `t` is `TypeError` -: 58:function isTypeError(Type* t): bool -: 59:{ 92928: 60: return t.kind == TokenType.invalid; -: 61:} -: 62: -: 63:/// Returns: a TypeFunction if `t.resolved()` is one else `null` -: 64:function asTypeFunction(Type* t): TypeFunction* -: 65:{ 44933: 66: t = t.resolved(); 44933: 67: return t.kind == $function ? *((&t):TypeFunction**) else null; -: 68:} -: 69: -: 70:/// Returns: a TypeIdentifier if `t` is one else `null` -: 71:function asTypeIdentifier(Type* t): TypeIdentifier* -: 72:{ 2216: 73: return t.kind == id ? *((&t):TypeIdentifier**) else null; -: 74:} -: 75: -: 76:/// Returns: a TypeModified if `t.resolved()` is one else `null` -: 77:function asTypeModified(Type* t): TypeModified* -: 78:{ 84398: 79: t = t.resolved(); 84398: 80: switch t.kind do -: 81: { 36829: 82: on mul, tkSta, tkSlice, tkEnumSet, tkRca do return *((&t):TypeModified**); 47569: 83: else do return null; -: 84: } -: 85:} -: 86: -: 87:/// Returns: if `t` is `TypeNull` -: 88:function isTypeNull(Type* t): bool -: 89:{ 8329: 90: return t.kind == TokenType.$null; -: 91:} -: 92: -: 93:/// Returns: a TypeOverload if `t.resolved()` is one else `null` -: 94:function asTypeOverload(Type* t): TypeOverload* -: 95:{ 80: 96: t = t.resolved(); 80: 97: return t.kind == $overload ? *((&t):TypeOverload**) else null; -: 98:} -: 99: -: 100:/// Returns: a TypePointer if `t.resolved()` is one else `null` -: 101:function asTypePointer(Type* t): TypePointer* -: 102:{ 412797: 103: t = t.resolved(); 412797: 104: return t.kind == mul ? *((&t):TypePointer**) else null; -: 105:} -: 106: -: 107:/// Returns: a TypeStaticArray if `t.resolved()` is one else `null` -: 108:function asTypeStaticArray(Type* t): TypeStaticArray* -: 109:{ 163517: 110: t = t.resolved(); 163517: 111: return t.kind == tkSta ? *((&t):TypeStaticArray**) else null; -: 112:} -: 113: -: 114:/// Returns: a TypeStaticArray if `t.resolved()` is one else `null` -: 115:function asTypeRcArray(Type* t): TypeRcArray* -: 116:{ 122824: 117: t = t.resolved(); 122824: 118: return t.kind == tkRca ? *((&t):TypeRcArray**) else null; -: 119:} -: 120: -: 121:/// Returns: if `t` is `TypeS8` -: 122:function isTypeS8(Type* t): bool -: 123:{ 1226: 124: return t.kind == TokenType.$s8; -: 125:} -: 126: -: 127:/// Returns: a TypeSlice if `t.resolved()` is one else `null` -: 128:function asTypeSlice(Type* t): TypeSlice* -: 129:{ 95726: 130: t = t.resolved(); 95726: 131: return t.kind == tkSlice ? *((&t):TypeSlice**) else null; -: 132:} -: 133: -: 134:/// Returns: a TypeStruct if `t.resolved()` is one else `null` -: 135:function asTypeStruct(Type* t): TypeStruct* -: 136:{ 3830: 137: t = t.resolved(); 3830: 138: return t.kind == $struct ? *((&t):TypeStruct**) else null; -: 139:} -: 140: -: 141:/// Returns: a `TypeTuple*` if `t.resolved()` is one else `null` -: 142:function asTypeTuple(Type* t): TypeTuple* -: 143:{ 119134: 144: t = t.resolved(); 119134: 145: return t.kind == comma ? *((&t):TypeTuple**) else null; -: 146:} -: 147: -: 148:/// Returns: a TypeClass if `t.resolved()` is one else `null` -: 149:function asTypeUnion(Type* t): TypeUnion* -: 150:{ 3640: 151: t = t.resolved(); 3640: 152: return t.kind == $union ? *((&t):TypeUnion**) else null; -: 153:} -: 154: -: 155:/// Returns: if `t` is `TypeVoid` -: 156:function isTypeVoid(Type* t): bool -: 157:{ 29057: 158: return t.kind == ExtendedTokenType.tkVoid; -: 159:} -: 160: -: 161:/// Puts the inheritance chain in `chain` starting from the base and excluding `derived`. -: 162:function getInheritanceChain(Type* derived; var Type*[+] result) -: 163:{ 33189: 164: var TypeAggregate* ta = asTypeAggregate(derived); 33189: 165: if ta do -: 166: { 33189: 167: if ta.declaration.inheritanceList.length do -: 168: { 24672: 169: getInheritanceChain(ta.declaration.inheritanceList.ptr[0], result); 24672: 170: result ~= ta.declaration.inheritanceList.ptr[0]; -: 171: } -: 172: } 33189: 173:} -: 174: -: 175:/// Returns: if `derived` inherits of `base` -: 176:function inheritsOf(Type* derived; Type* base): bool -: 177:{ 8595: 178: var TypeClass* cd = asTypeClass(derived); 8595: 179: var TypeClass* cb = asTypeClass(base); 8595: 180: if !cd || !cb do 3: 181: return false; 8592: 182: if cd.declaration:u8* == cb.declaration:u8* do 2918: 183: return true; 5674: 184: if cd.declaration.inheritanceList.length do 5288: 185: return inheritsOf(cd.declaration.inheritanceList[0], base); 386: 186: return false; -: 187:} -: 188: -: 189:/// Returns: the smaller integer type that the input parameter can fit into -: 190:function integerTypeFor(const u64 value): Type* -: 191:{ 35: 192: var Type* result = TypeU64.instance(); 35: 193: if value <= 0xFF do 29: 194: result = TypeU8.instance(); 6: 195: else do if value <= 0xFFFF do 5: 196: result = TypeU16.instance(); 1: 197: else do if value <= 0xFFFF_FFFF do 1: 198: result = TypeU32.instance(); 35: 199: return result; -: 200:} -: 201: -: 202:/// Returns: the type, stripping the modifiers, e.g `TypeU8.instance()` for `u8**[3][]`. -: 203:function mostModified(Type* t): Type* -: 204:{ 72350: 205: var TypeModified* tm = t.asTypeModified(); 72350: 206: return tm ? mostModified(tm.modified) else t.resolved(); -: 207:} -: 208: -: 209:/// Returns the base type of the members of an enum -: 210:function getEnumRootType(EnumDeclaration* ed): Type* -: 211:{ 985: 212: while ed do -: 213: { 1059: 214: if !ed.base do 985: 215: return ed.type; 74: 216: ed = asTypeEnum(ed.base).declaration; -: 217: } -: 218: assert(0); -: 219:} -: 220: -: 221:@final class TypeAppliedGeneric : Type -: 222:{ -: 223: /// -: 224: var Expression* applyExpression; -: 225: /// -: 226: @constructor function create(Expression* applyExpression) -: 227: { 43: 228: this.kind = $apply; 43: 229: this.applyExpression = applyExpression; 43: 230: } -: 231: /// -: 232: @override function free() -: 233: { 0: 234: applyExpression?.free(); 0: 235: super(); 0: 236: } -: 237: /// -: 238: @override function accept(AstVisitor* visitor) -: 239: { -: 240: assert(0); -: 241: } -: 242: /// -: 243: @override function resolved(): Type* -: 244: { -: 245: assert(0); -: 246: } -: 247: /// -: 248: @override function isVariableType(): bool -: 249: { -: 250: assert(0); -: 251: } -: 252:} -: 253: -: 254:/// TypeAggregate -: 255:class TypeAggregate : TypeDeclared -: 256:{ -: 257: /// -: 258: @@Semantic var AggregateDeclaration* declaration; -: 259: /// -: 260: @constructor function create(AggregateDeclaration* declaration) -: 261: { 1060: 262: super.create(declaration); 1060: 263: this.declaration = declaration; 1060: 264: this.align = session.ptr_size; 1060: 265: } -: 266: /// 345: 267: @override function accept(AstVisitor* visitor) {} -: 268:} -: 269: -: 270:/// TypeAuto -: 271:@final class TypeAuto : TypeSingleton -: 272:{ -: 273:protection (private) -: 274: -: 275: static var TypeAuto* unique; -: 276: -: 277: @destructor static function statidDtor() -: 278: { 374: 279: delete unique; 374: 280: } -: 281: -: 282: @constructor static function statidCtor() -: 283: { 374: 284: unique = (new TypeAuto).create(); 374: 285: } -: 286: -: 287: @constructor function create() -: 288: { 374: 289: this.kind = $auto; 374: 290: } -: 291: -: 292:protection (public) -: 293: -: 294: /// Returns: the unique instance -: 295: static function instance(): TypeAuto* -: 296: { 3075: 297: return unique; -: 298: } -: 299: /// 479: 300: @override function isVariableType(): bool { return false; } -: 301:} -: 302: -: 303:/// The type for `bool` -: 304:@final class TypeBool : TypeSingleton -: 305:{ -: 306:protection (private) -: 307: -: 308: var static TypeBool* unique; -: 309: -: 310: @destructor static function statidDtor() -: 311: { 748: 312: if unique do delete unique; 374: 313: } -: 314: -: 315: @constructor static function statidCtor() -: 316: { 374: 317: unique = (new TypeBool).create(); 374: 318: } -: 319: -: 320: @constructor function create() -: 321: { 374: 322: this.kind = $bool; 374: 323: this.size = 1; 374: 324: } -: 325: -: 326:protection (public) -: 327: -: 328: /// Returns: the unique instance -: 329: static function instance(): TypeBool* -: 330: { 21464: 331: return unique; -: 332: } -: 333:} -: 334: -: 335:/// The type for `class`. Wraps a ClassDeclaration. -: 336:@final class TypeClass : TypeAggregate -: 337:{ -: 338: /// -: 339: @@Semantic var ClassDeclaration* declaration; -: 340: /// -: 341: @constructor function create(ClassDeclaration* declaration) -: 342: { 494: 343: super(declaration); 494: 344: this.kind = $class; 494: 345: this.declaration = declaration; 494: 346: } -: 347:} -: 348: -: 349:/// Base class for types that are created for a specific Declaration. -: 350:class TypeDeclared : Type -: 351:{ -: 352: /// The matching Declaration -: 353: var Declaration* declaration; -: 354: /// -: 355: @constructor function create(Declaration* declaration) -: 356: { 17676: 357: this.declaration = declaration; 17676: 358: } -: 359: /// -: 360: @final @override function asSymbol(): Symbol* -: 361: { 50128: 362: return declaration.symbol; -: 363: } -: 364: /// -: 365: @override function isVariableType(): bool -: 366: { 8169: 367: return !declaration.genericParameters || declaration.genericParameters.applied(); -: 368: } -: 369:} -: 370: -: 371:/// TypeEcho -: 372:@final class TypeEcho : Type -: 373:{ -: 374: /// the wrapped echo() -: 375: var Expression* expression; -: 376: /// -: 377: @constructor function create(Expression* expression) -: 378: { 23: 379: this.kind = $echo; 23: 380: this.expression = expression; 23: 381: } -: 382: /// -: 383: @override function free() -: 384: { 3: 385: expression?.free(); 3: 386: super(); 3: 387: } -: 388: /// -: 389: @override function resolved(): Type* -: 390: { -: 391: // type sema replace with the echo-ed thing -: 392: assert(0); -: 393: } -: 394:} -: 395: -: 396:/// TypeElemens, like an IndexExpression that get replaced by a TypeTuple -: 397:@final class TypeElements : Type -: 398:{ -: 399: /// -: 400: var Type* elements; -: 401: /// -: 402: var Expression*[+] indexes; -: 403: /// -: 404: var bool isSlice; -: 405: /// -: 406: @constructor function create (Type* elements; Expression*[] indexes) -: 407: { 26: 408: this.kind = leftSquare; 26: 409: this.elements = elements; 26: 410: this.indexes = indexes; 26: 411: } -: 412: /// -: 413: @override function accept(AstVisitor* visitor) -: 414: { 9: 415: visitor.visitType(elements); 9: 416: foreach var auto i in indexes do 19: 417: visitor.visitExpression(i); 9: 418: } -: 419: /// -: 420: @override function free() -: 421: { 6: 422: elements.free(); 6: 423: foreach var auto i in indexes do 12: 424: i.free(); 6: 425: indexes.decref; 6: 426: super(); 6: 427: } -: 428: /// -: 429: @override function isEqual(Object* other): bool -: 430: { -: 431: assert(0, "should have been replaced by a TypeTuple"); -: 432: } -: 433: /// -: 434: @override function isVariableType(): bool { assert(0); } -: 435:} -: 436: -: 437:/// The type for empty ArrayExpression -: 438:@final class TypeEmptyArray : TypeSingleton -: 439:{ -: 440:protection (private) -: 441: -: 442: static var TypeEmptyArray* unique; -: 443: -: 444: @destructor static function statidDtor() -: 445: { 433: 446: if unique do delete unique; 374: 447: } -: 448: -: 449: @constructor function create() -: 450: { 59: 451: this.kind = rightSquare; 59: 452: } -: 453: -: 454:protection (public) -: 455: -: 456: /// Returns: the unique instance -: 457: static function instance(): TypeEmptyArray* -: 458: { 1152: 459: return unique ?= (new TypeEmptyArray).create(); -: 460: } -: 461: /// 1: 462: @override function isVariableType(): bool { return false; } -: 463:} -: 464: -: 465:/// The type for `enum`. Wraps a EnumDeclaration. -: 466:@final class TypeEnum : TypeDeclared -: 467:{ -: 468: /// -: 469: var EnumDeclaration* declaration; -: 470: /// -: 471: @constructor function create(EnumDeclaration* declaration) -: 472: { 440: 473: super(declaration); 440: 474: this.kind = $enum; 440: 475: this.declaration = declaration; 440: 476: } -: 477: /// 71: 478: @override function accept(AstVisitor* visitor) {} -: 479: /// 2892: 480: @override function isIntegral(): bool { return true; } -: 481: /// 1255: 482: @final @override function isSigned(): bool { return declaration.type.isSigned(); } -: 483:} -: 484: -: 485:/// The type for bool[SomeEnum] -: 486:@final class TypeEnumSet : TypeModified -: 487:{ -: 488: /// -: 489: var EnumDeclaration* declaration; -: 490: /// -: 491: @constructor function create(EnumDeclaration* declaration) -: 492: { 49: 493: super(declaration.asTypeDeclared); 49: 494: this.kind = tkEnumSet; 49: 495: this.declaration = declaration; 49: 496: this.size = declaration.type.size; 49: 497: this.align = declaration.type.size; 49: 498: } -: 499: /// -: 500: @override function isEqual(Object* other): bool -: 501: { 119: 502: var TypeEnumSet* tes = other:TypeEnumSet*; 119: 503: return tes && tes.modified.resolved() == modified.resolved(); -: 504: } -: 505:} -: 506: -: 507:/// TypeError -: 508:@final class TypeError : TypeSingleton -: 509:{ -: 510:protection (private) -: 511: -: 512: static var TypeError* unique; -: 513: -: 514: @destructor static function statidDtor() -: 515: { 748: 516: if unique do delete unique; 374: 517: } -: 518: -: 519: @constructor static function statidCtor() -: 520: { 374: 521: unique = (new TypeError).create(); 374: 522: } -: 523: -: 524: @constructor function create() -: 525: { 374: 526: this.kind = invalid; 374: 527: } -: 528: -: 529:protection (public) -: 530: -: 531: /// Returns: the unique instance -: 532: static function instance(): TypeError* -: 533: { 14205: 534: return unique; -: 535: } -: 536: /// 63: 537: @override function isVariableType(): bool { return false; } -: 538:} -: 539: -: 540:/// -: 541:class TypeFloating : TypeSingleton -: 542:{ -: 543: /// 263: 544: @final @override function isFloating(): bool { return true; } -: 545: /// 121: 546: @final @override function isSigned(): bool { return true; } -: 547:} -: 548: -: 549:/// TypeF32 -: 550:@final class TypeF32 : TypeFloating -: 551:{ -: 552:protection (private) -: 553: -: 554: static var TypeF32* unique; -: 555: -: 556: @destructor static function statidDtor() -: 557: { 576: 558: if unique do delete unique; 374: 559: } -: 560: -: 561: @constructor function create() -: 562: { 202: 563: this.kind = $f32; 202: 564: this.size = 32; 202: 565: } -: 566: -: 567:protection (public) -: 568: -: 569: /// Returns: the unique instance -: 570: static function instance(): TypeF32* -: 571: { 314: 572: return unique ?= (new TypeF32).create(); -: 573: } -: 574:} -: 575: -: 576:/// TypeF64 -: 577:@final class TypeF64 : TypeFloating -: 578:{ -: 579:protection (private) -: 580: -: 581: static var TypeF64* unique; -: 582: -: 583: @destructor static function statidDtor() -: 584: { 584: 585: if unique do delete unique; 374: 586: } -: 587: -: 588: @constructor function create() -: 589: { 210: 590: this.kind = $f64; 210: 591: this.size = 64; 210: 592: } -: 593: -: 594:protection (public) -: 595: -: 596: /// Returns: the unique instance -: 597: static function instance(): TypeF64* -: 598: { 539: 599: return unique ?= (new TypeF64).create(); -: 600: } -: 601:} -: 602: -: 603:/// The type for `function`. Wraps a FunctionDeclaration. -: 604:@final class TypeFunction : TypeDeclared -: 605:{ -: 606:protection(private) -: 607: -: 608: static var TypeFunction* utt; -: 609: -: 610:protection(public) -: 611: -: 612: var bool ownDeclaration; -: 613: /// -: 614: var FunctionDeclaration* declaration; -: 615: /// -: 616: @constructor function create(FunctionDeclaration* declaration; bool ownDeclaration) -: 617: { 16124: 618: super(declaration); 16124: 619: this.kind = $function; 16124: 620: this.declaration = declaration; 16124: 621: this.ownDeclaration = ownDeclaration; 16124: 622: } -: 623: /// -: 624: @override function free() -: 625: { -: 626: // if decl was created by parsing a type... 57: 627: if ownDeclaration && declaration do 21: 628: declaration.free(); 57: 629: super(); 57: 630: } -: 631: /// -: 632: @override function accept(AstVisitor* visitor) -: 633: { 142: 634: visitor.visitDeclaration(declaration); 142: 635: } -: 636: /// -: 637: @destructor static function freeUtf() -: 638: { 382: 639: if utt do delete utt; 374: 640: } -: 641: /// Returns: the prototype for `@unittest` functions. -: 642: static function unittestType(): TypeFunction* -: 643: { 18: 644: if !utt do -: 645: { 8: 646: var FunctionDeclaration* fd = (new FunctionDeclaration).create((0,0)); 8: 647: fd.stc += $static; 8: 648: fd.returnType = TypeVoid.instance(); 8: 649: fd.progress = SemanticProgress.done; 8: 650: fd.symbol = (new Symbol).createUnamed(Root.instance()); 8: 651: fd.asTypeDeclared = utt = (new TypeFunction).create(fd, true); -: 652: } 18: 653: return utt; -: 654: } -: 655: /// Returns: same as `==` overload but the `this` parameter or the resturn type can be optionally ignored. -: 656: function isEqualEx(Object* other; bool ignoreThis; bool ignoreRet): bool -: 657: { 1061: 658: var TypeFunction* tf = other:TypeFunction*; 1061: 659: if !tf do 47: 660: return false; -: 661: 1014: 662: var auto thisFd = declaration; 1014: 663: var auto thatFd = tf.declaration; -: 664: 1014: 665: var bool sameReturn = true; 1014: 666: if !ignoreRet do -: 667: { 929: 668: sameReturn = false; 929: 669: var auto rt1 = thisFd.returnType.resolved(); 929: 670: var auto rt2 = thatFd.returnType.resolved(); 929: 671: var auto tp1 = asTypePointer(rt1); 929: 672: var auto tp2 = asTypePointer(rt2); 929: 673: if rt1 == rt2 do 917: 674: sameReturn = true; 12: 675: else do if tp1 && tp2 do 2: 676: sameReturn = inheritsOf(tp1.modified, tp2.modified); -: 677: } -: 678: 1014: 679: const bool sameVariadic = (isCeeVariadic in thisFd.flags) == (isCeeVariadic in thatFd.flags); 1014: 680: var bool sameParameters = thisFd.parameters.length == thatFd.parameters.length; -: 681: 1014: 682: if sameParameters do -: 683: { 991: 684: foreach const auto i in 0 .. thisFd.parameters.length do -: 685: { 1664: 686: var VariableDeclaration* p0 = thisFd.parameters.ptr[i]; 1664: 687: var VariableDeclaration* p1 = thatFd.parameters[i]; 1664: 688: if p0.name == thisToken() && p1.name == thisToken() && ignoreThis do 852: 689: continue; 812: 690: if p0.isVar() == p1.isVar() && p0.type.resolved() == p1.type.resolved() do 735: 691: continue; 77: 692: sameParameters = false; 77: 693: break; -: 694: } -: 695: } -: 696: 1014: 697: return sameReturn && sameParameters && sameVariadic; -: 698: } -: 699: /// -: 700: @override function isEqual(Object* other): bool -: 701: { 123: 702: return isEqualEx(other, false, false); -: 703: } -: 704: /// -: 705: function isCovariantWith(TypeFunction* other): bool -: 706: { -: 707: -: 708: static function isTypeCovariantWith(Type* t0; Type* t1): bool -: 709: { 8: 710: t0 = t0.resolved(); 8: 711: t1 = t1.resolved(); 8: 712: var TypePointer* tp0 = t0.asTypePointer(); 8: 713: var TypePointer* tp1 = t1.asTypePointer(); 8: 714: var TypeClass* tc0 = tp0 ? tp0.modified.asTypeClass() else null; 8: 715: var TypeClass* tc1 = tp1 ? tp1.modified.asTypeClass() else null; 8: 716: return (t0 == t1) || (tc0 && tc1 && tc0.inheritsOf(tc1)); -: 717: } -: 718: 5: 719: var FunctionDeclaration* thisFd = declaration; 5: 720: var FunctionDeclaration* thatFd = other.declaration; -: 721: 5: 722: const bool sameReturn = thisFd.returnType.isTypeCovariantWith(thatFd.returnType); 5: 723: const bool sameVariadic = (isCeeVariadic in thisFd.flags) == (isCeeVariadic in thatFd.flags); 5: 724: var bool sameParameters = thisFd.parameters.length == thatFd.parameters.length; -: 725: 5: 726: if sameParameters do -: 727: { 3: 728: foreach const auto i in 0 .. thisFd.parameters.length do -: 729: { 3: 730: var VariableDeclaration* p0 = thisFd.parameters.ptr[i]; 3: 731: var VariableDeclaration* p1 = thatFd.parameters[i]; 3: 732: if p0.isVar() == p1.isVar() && p0.type.isTypeCovariantWith(p1.type) do 2: 733: continue; 1: 734: sameParameters = false; 1: 735: break; -: 736: } -: 737: } 5: 738: return sameReturn && sameParameters && sameVariadic; -: 739: } -: 740: /// 8: 741: @override function isVariableType(): bool { return false; } -: 742:} -: 743: -: 744:/// The type for types that resolve to other types. -: 745:@final class TypeIdentifier : Type -: 746:{ -: 747: /// -: 748: var Token* identifier; -: 749: /// -: 750: var TypeIdentifier* next; -: 751: /// -: 752: var Expression*[+] genericArguments; -: 753: /// -: 754: @@Semantic var Type* solved; -: 755: /// -: 756: @constructor function create(Token* identifier) -: 757: { 10649: 758: this.kind = id; 10649: 759: this.identifier = identifier; 10649: 760: } -: 761: /// -: 762: @override function free() -: 763: { -: 764: 1077: 765: next?.free(); 1099: 766: foreach var auto gp in genericArguments do gp.free(); 1077: 767: genericArguments.decref; 1077: 768: super(); 1077: 769: } -: 770: /// 0: 771: function isSolved(): bool {return solved != null;} -: 772: /// -: 773: @override function accept(AstVisitor* visitor) -: 774: { 14218: 775: if next do visitor.visitType(next); 13197: 776: } -: 777: /// -: 778: function chain(): Token*[+] -: 779: { -: 780: var Token*[+] result; 1072: 781: var TypeIdentifier* current = this; 1072: 782: while current do -: 783: { 1273: 784: result ~= current.identifier; 1273: 785: current = current.next; -: 786: } 1072: 787: return result; -: 788: } -: 789: /// -: 790: @override function asSymbol(): Symbol* -: 791: { 1022: 792: return solved:u8* ? solved.asSymbol() else null; -: 793: } -: 794: /// -: 795: @override function isEqual(Object* other): bool -: 796: { 1: 797: assert (!solved, "missing `.resolved()` when comparing a TypeIdentifier"); 1: 798: return false; -: 799: } -: 800: @override function resolved(): Type* -: 801: { 410377: 802: var TypeIdentifier* tid = this; 410639: 803: while tid.next do tid = tid.next; 410377: 804: return tid.solved ? tid.solved.resolved() else tid; -: 805: } -: 806: /// 7204: 807: @override function isVariableType(): bool { return resolved()?.isVariableType(); } -: 808:} -: 809: -: 810:/// -: 811:class TypeIntegral : TypeSingleton -: 812:{ 31494: 813: @final @override function isIntegral(): bool { return true; } -: 814:} -: 815: -: 816:/// -: 817:class TypeSignedIntegral : TypeIntegral -: 818:{ 3114: 819: @final @override function isSigned(): bool { return true; } -: 820:} -: 821: -: 822:/// Base Type for pointer types and array types. -: 823:class TypeModified : Type -: 824:{ -: 825: /// The type that is modified -: 826: var Type* modified; -: 827: /// -: 828: @constructor function create(Type* modified) -: 829: { 26010: 830: this.modified = modified; 26010: 831: } -: 832: /// -: 833: @override function free() -: 834: { -: 835: //printf("TypeModified.free() this=%p\n", this); 275: 836: modified?.free(); 275: 837: super(); 275: 838: } -: 839: /// -: 840: @override function accept(AstVisitor* visitor) -: 841: { 32252: 842: if modified do visitor.visitType(modified); 16126: 843: } -: 844: /// 10509: 845: @override function isVariableType(): bool { return modified.isVariableType(); } -: 846:} -: 847: -: 848:/// TypeNull -: 849:@final class TypeNull : TypeSingleton -: 850:{ -: 851:protection (private) -: 852: -: 853: static var TypeNull* unique; -: 854: -: 855: @destructor static function statidDtor() -: 856: { 441: 857: if unique do delete unique; 374: 858: } -: 859: -: 860: @constructor function create() -: 861: { 67: 862: this.kind = $null; 67: 863: } -: 864: -: 865:protection (public) -: 866: -: 867: /// Returns: the unique instance -: 868: static function instance(): TypeNull* -: 869: { 970: 870: return unique ?= (new TypeNull).create(); -: 871: } -: 872: /// 4: 873: @override function isVariableType(): bool { return false; } -: 874:} -: 875: -: 876:/// TypeOverload -: 877:@final class TypeOverload : TypeDeclared -: 878:{ -: 879: /// -: 880: var OverloadDeclaration* declaration; -: 881: /// -: 882: @constructor function create(OverloadDeclaration* declaration) -: 883: { 52: 884: super(declaration); 52: 885: this.kind = $overload; 52: 886: this.declaration = declaration; 52: 887: } -: 888: /// -: 889: @override function accept(AstVisitor* visitor) -: 890: { 0: 891: visitor.visitDeclaration(declaration); 0: 892: } -: 893: /// 2: 894: @override function isVariableType(): bool { return false; } -: 895:} -: 896: -: 897:/// The type for builtin pointers. -: 898:@final class TypePointer : TypeModified -: 899:{ -: 900: /// Rather use the pointerOf() to create a new TypePointer. -: 901: @constructor function create(Type* modified) -: 902: { -: 903: //printf("TypePointer.create() this=%p\n", this); 20303: 904: super(modified); 20303: 905: this.kind = mul; 20303: 906: this.size = session.ptr_size; 20303: 907: this.align = session.ptr_size; 20303: 908: } -: 909: @override function free() -: 910: { -: 911: //printf("TypePointer.free() this=%p\n", this); 237: 912: super(); 237: 913: } -: 914: /// -: 915: @override function isEqual(Object* other): bool -: 916: { 24441: 917: var TypePointer* tp = other:TypePointer*; 24441: 918: return tp && tp.modified.resolved() == modified.resolved(); -: 919: } -: 920: /// -: 921: @override function isVariableType(): bool -: 922: { 8728: 923: if asTypeFunction(modified) do 99: 924: return true; 8629: 925: return super(); -: 926: } -: 927:} -: 928: -: 929:/// TypeRange -: 930:@final class TypeRange : TypeSingleton -: 931:{ -: 932:protection (private) -: 933: -: 934: static var TypeRange* unique; -: 935: -: 936: @destructor static function statidDtor() -: 937: { 658: 938: if unique do delete unique; 374: 939: } -: 940: -: 941: @constructor function create() -: 942: { 284: 943: this.kind = dotDot; 284: 944: } -: 945: -: 946:protection (public) -: 947: -: 948: /// Returns: the unique instance -: 949: static function instance(): TypeRange* -: 950: { 4268: 951: return unique ?= (new TypeRange).create(); -: 952: } -: 953: /// 5: 954: @override function isVariableType(): bool { return false; } -: 955:} -: 956: -: 957:/// The type for builtin ref counted arrays -: 958:@final class TypeRcArray : TypeModified -: 959:{ -: 960: /// -: 961: var u8 nestedRcArrayDims; -: 962: /// -: 963: @constructor function create(Type* modified) -: 964: { 1168: 965: super(modified); 1168: 966: this.kind = tkRca; 1168: 967: this.size = session.ptr_size; 1168: 968: this.align = session.ptr_size; 1168: 969: } -: 970: /// -: 971: @override function isEqual(Object* other): bool -: 972: { 487: 973: var TypeRcArray* tra = other:TypeRcArray*; 487: 974: return tra && tra.modified.resolved() == modified.resolved(); -: 975: } -: 976:} -: 977: -: 978:/// TypeS16 -: 979:@final class TypeS16 : TypeSignedIntegral -: 980:{ -: 981:protection (private) -: 982: -: 983: static var TypeS16* unique; -: 984: -: 985: @destructor static function statidDtor() -: 986: { 577: 987: if unique do delete unique; 374: 988: } -: 989: -: 990: @constructor function create() -: 991: { 203: 992: this.kind = $s16; 203: 993: this.size = 16; 203: 994: } -: 995: -: 996:protection (public) -: 997: -: 998: /// Returns: the unique instance -: 999: static function instance(): TypeS16* -:1000: { 368:1001: return unique ?= (new TypeS16).create(); -:1002: } -:1003:} -:1004: -:1005:/// TypeS32 -:1006:@final class TypeS32 : TypeSignedIntegral -:1007:{ -:1008:protection (private) -:1009: -:1010: static var TypeS32* unique; -:1011: -:1012: @destructor static function statidDtor() -:1013: { 669:1014: if unique do delete unique; 374:1015: } -:1016: -:1017: @constructor function create() -:1018: { 295:1019: this.kind = $s32; 295:1020: this.size = 32; 295:1021: } -:1022: -:1023:protection (public) -:1024: -:1025: /// Returns: the unique instance -:1026: static function instance(): TypeS32* -:1027: { 3496:1028: return unique ?= (new TypeS32).create(); -:1029: } -:1030:} -:1031: -:1032:/// TypeS64 -:1033:@final class TypeS64 : TypeSignedIntegral -:1034:{ -:1035:protection (private) -:1036: -:1037: static var TypeS64* unique; -:1038: -:1039: @destructor static function statidDtor() -:1040: { 588:1041: if unique do delete unique; 374:1042: } -:1043: -:1044: @constructor function create() -:1045: { 214:1046: this.kind = $s64; 214:1047: this.size = 64; 214:1048: } -:1049: -:1050:protection (public) -:1051: -:1052: /// Returns: the unique instance -:1053: static function instance(): TypeS64* -:1054: { 703:1055: return unique ?= (new TypeS64).create(); -:1056: } -:1057:} -:1058: -:1059:/// TypeS8 -:1060:@final class TypeS8 : TypeSignedIntegral -:1061:{ -:1062:protection (private) -:1063: -:1064: static var TypeS8* unique; -:1065: -:1066: @destructor static function statidDtor() -:1067: { 625:1068: if unique do delete unique; 374:1069: } -:1070: -:1071: @constructor function create() -:1072: { -:1073: //printf("TypeS8.create() this=%p\n", this); 251:1074: this.kind = $s8; 251:1075: this.size = 8; 251:1076: } -:1077: -:1078:protection (public) -:1079: -:1080: /// Returns: the unique instance -:1081: static function instance(): TypeS8* -:1082: { 7399:1083: return unique ?= (new TypeS8).create(); -:1084: } -:1085:} -:1086: -:1087:/// Protect type with unique instances against multiple frees -:1088:class TypeSingleton : Type -:1089:{ 1377:1090: @override function free(){} -:1091:} -:1092: -:1093:/// The type for builtin slices -:1094:@final class TypeSlice : TypeModified -:1095:{ -:1096: /// -:1097: @constructor function create(Type* modified) -:1098: { 3282:1099: super(modified); 3282:1100: this.kind = tkSlice; 3282:1101: this.size = session.ptr_size * 2; 3282:1102: this.align = session.ptr_size; 3282:1103: } -:1104: /// -:1105: @override function isEqual(Object* other): bool -:1106: { 1623:1107: var TypeSlice* tsl = other:TypeSlice*; 1623:1108: return tsl && tsl.modified.resolved() == modified.resolved(); -:1109: } -:1110:} -:1111: -:1112:/// The type for `ssize` -:1113:function TypeSSize(): Type* -:1114:{ 212:1115: return session.ptr_size == 32 ? TypeS32.instance() else TypeS64.instance(); -:1116:} -:1117: -:1118:/// The type for `struct`. Wraps a StructDeclaration. -:1119:@final class TypeStruct : TypeAggregate -:1120:{ -:1121: /// -:1122: @@Semantic var StructDeclaration* declaration; -:1123: /// -:1124: var TypeTuple* asTypeTupleCache; -:1125: /// -:1126: @constructor function create(StructDeclaration* declaration) -:1127: { 538:1128: super(declaration); 538:1129: this.kind = $struct; 538:1130: this.declaration = declaration; 538:1131: } -:1132: -:1133: /// Returns: the equivalent TypeTuple -:1134: function toTypeTuple(): TypeTuple* -:1135: { 25:1136: if asTypeTupleCache do 14:1137: return asTypeTupleCache; 11:1138: var auto j = 0; 11:1139: var auto types = (new Type*[+])(declaration.body.items.length); 11:1140: foreach var auto d in declaration.body.items do -:1141: { 32:1142: var auto vd = asVariableDeclaration(d); 32:1143: if !vd || vd.isStatic() do 11:1144: continue; 21:1145: types[j++] = vd.type; -:1146: } 11:1147: types.length = j; 11:1148: asTypeTupleCache = (new TypeTuple).create(types); 11:1149: asTypeTupleCache.progress = done; 11:1150: return asTypeTupleCache; -:1151: } -:1152:} -:1153: -:1154:/// The type for static arrays -:1155:@final class TypeStaticArray : TypeModified -:1156:{ -:1157: /// The expression that gives the length -:1158: var Expression* lengthExp; -:1159: /// -:1160: @constructor function create(Type* modified; Expression* lengthExp) -:1161: { 1208:1162: super(modified); 1208:1163: this.kind = tkSta; 1208:1164: this.lengthExp = lengthExp; 1208:1165: this.align = session.ptr_size; 1208:1166: } -:1167: /// -:1168: @override function free() -:1169: { 5:1170: lengthExp?.free(); 5:1171: super(); 5:1172: } -:1173: /// -:1174: @override function accept(AstVisitor* visitor) -:1175: { 1198:1176: if lengthExp do visitor.visitExpression(lengthExp); 599:1177: super.accept(visitor); 599:1178: } -:1179: /// Returns: the length of the static array. -:1180: function length(): u32 -:1181: { 10837:1182: assert(lengthExp.type, "expressionSemantic not run on static array lengthExp"); 10837:1183: var IntegerExpression* ie = lengthExp.asIntegerExp(); 10837:1184: return ie ? ie.value:u32 else 0; -:1185: } -:1186: /// -:1187: @override function isEqual(Object* other): bool -:1188: { 614:1189: if var TypeStaticArray* tsa = other:TypeStaticArray* do 173:1190: return tsa.modified.resolved() == modified.resolved() && tsa.length() == length(); 134:1191: return false; -:1192: } -:1193:} -:1194: -:1195:/// TypeTuple -:1196:@final class TypeTuple : Type -:1197:{ -:1198: /// -:1199: var Type*[+] types; -:1200: /// -:1201: var bool needsExpansion; -:1202: /// -:1203: @constructor function create(Type*[] types; bool needsExpansion = false) -:1204: { 253:1205: this.kind = comma; 253:1206: this.types = types; 253:1207: this.needsExpansion = needsExpansion; 253:1208: } -:1209: /// -:1210: @override function accept(AstVisitor* visitor) -:1211: { 106:1212: foreach var auto t in types do 252:1213: visitor.visitType(t); 106:1214: } -:1215: /// -:1216: @override function free() -:1217: { 13:1218: foreach var auto t in types do 27:1219: t.free(); 13:1220: types.decref; 13:1221: super(); 13:1222: } -:1223: /// -:1224: @override function isEqual(Object* other): bool -:1225: { 234:1226: if var auto tt = other:TypeTuple* do -:1227: { 84:1228: if tt.types.length != types.length do 0:1229: return false; 84:1230: foreach (const auto i; var auto t) in types do 176:1231: if t.resolved() != tt.types[i].resolved() do 2:1232: return false; 82:1233: return true; -:1234: } 33:1235: return false; -:1236: } -:1237: /// -:1238: @override function isVariableType(): bool -:1239: { 94:1240: if !types.length do 3:1241: return false; 91:1242: foreach var auto t in types do 170:1243: if !t.isVariableType() do 3:1244: return false; 88:1245: return true; -:1246: } -:1247: /// Returns: if a `TupleExpression` of this type can be implictly cast to the result type -:1248: function isSingleElement(): Type* -:1249: { 42:1250: if types.length != 1 do 30:1251: return null; 24:1252: if var auto tt = asTypeTuple(types[0]) do 5:1253: return tt.isSingleElement(); 7:1254: return types[0].resolved(); -:1255: } -:1256: /// Returns: if a `TupleExpression` of this type can be implictly cast to `TypeVoid` -:1257: version none do function isVoid(): bool -:1258: { -:1259: if types.length == 0 do -:1260: return true; -:1261: if types.length != 1 do -:1262: return false; -:1263: if var auto tt = asTypeTuple(types[0]) do -:1264: return tt.isVoid(); -:1265: return isTypeVoid(types[0].resolved()); -:1266: } -:1267:} -:1268: -:1269:/// TypeU16 -:1270:@final class TypeU16 : TypeIntegral -:1271:{ -:1272:protection (private) -:1273: -:1274: static var TypeU16* unique; -:1275: -:1276: @destructor static function statidDtor() -:1277: { 573:1278: if unique do delete unique; 374:1279: } -:1280: -:1281: @constructor function create() -:1282: { 199:1283: this.kind = $u16; 199:1284: this.size = 16; 199:1285: } -:1286: -:1287:protection (public) -:1288: -:1289: /// Returns: the unique instance -:1290: static function instance(): TypeU16* -:1291: { 646:1292: return unique ?= (new TypeU16).create(); -:1293: } -:1294:} -:1295: -:1296:/// TypeU32 -:1297:@final class TypeU32 : TypeIntegral -:1298:{ -:1299:protection (private) -:1300: -:1301: static var TypeU32* unique; -:1302: -:1303: @destructor static function statidDtor() -:1304: { 665:1305: if unique do delete unique; 374:1306: } -:1307: -:1308: @constructor function create() -:1309: { 291:1310: this.kind = $u32; 291:1311: this.size = 32; 291:1312: } -:1313: -:1314:protection (public) -:1315: -:1316: /// Returns: the unique instance -:1317: static function instance(): TypeU32* -:1318: { 29818:1319: return unique ?= (new TypeU32).create(); -:1320: } -:1321:} -:1322: -:1323:/// TypeU64 -:1324:@final class TypeU64 : TypeIntegral -:1325:{ -:1326:protection (private) -:1327: -:1328: static var TypeU64* unique; -:1329: -:1330: @destructor static function statidDtor() -:1331: { 643:1332: if unique do delete unique; 374:1333: } -:1334: -:1335: @constructor function create() -:1336: { 269:1337: this.kind = $u64; 269:1338: this.size = 64; 269:1339: } -:1340: -:1341:protection (public) -:1342: -:1343: /// Returns: the unique instance -:1344: static function instance(): TypeU64* -:1345: { 29559:1346: return unique ?= (new TypeU64).create(); -:1347: } -:1348:} -:1349: -:1350:/// TypeU8 -:1351:@final class TypeU8 : TypeIntegral -:1352:{ -:1353:protection (private) -:1354: -:1355: static var TypeU8* unique; -:1356: -:1357: @destructor static function statidDtor() -:1358: { 621:1359: if unique do delete unique; 374:1360: } -:1361: -:1362: @constructor function create() -:1363: { 247:1364: this.kind = $u8; 247:1365: this.size = 8; 247:1366: } -:1367: -:1368:protection (public) -:1369: -:1370: /// Returns: the unique instance -:1371: static function instance(): TypeU8* -:1372: { 10065:1373: return unique ?= (new TypeU8).create(); -:1374: } -:1375:} -:1376: -:1377:/// TypeUnambiguous -:1378:@final class TypeUnambiguous : Type -:1379:{ -:1380: /// The type declared between parens -:1381: var Type* unambiguous; -:1382: /// -:1383: @constructor function create(Type* unambiguous) -:1384: { 35:1385: this.kind = tkUnamb; 35:1386: this.unambiguous = unambiguous; 35:1387: } -:1388: /// -:1389: @override function free() -:1390: { 3:1391: unambiguous?.free(); 3:1392: super(); 3:1393: } -:1394: /// -:1395: @override function accept(AstVisitor* visitor) -:1396: { 64:1397: if unambiguous do visitor.visitType(unambiguous); 32:1398: } -:1399: -:1400: @override function isVariableType(): bool { assert(0); } -:1401:} -:1402: -:1403:/// The type for `union`. Wraps a UnionDeclaration. -:1404:@final class TypeUnion : TypeAggregate -:1405:{ -:1406: /// -:1407: @@Semantic var UnionDeclaration* declaration; -:1408: /// -:1409: @constructor function create(UnionDeclaration* declaration) -:1410: { 28:1411: super(declaration); 28:1412: this.kind = $union; 28:1413: this.declaration = declaration; 28:1414: } -:1415:} -:1416: -:1417:/// The type for `usize` -:1418:function TypeUSize(): Type* -:1419:{ 25453:1420: return session.ptr_size == 32 ? TypeU32.instance() else TypeU64.instance(); -:1421:} -:1422: -:1423:/// TypeVoid -:1424:@final class TypeVoid : TypeSingleton -:1425:{ -:1426:protection (private) -:1427: -:1428: static var TypeVoid* unique; -:1429: -:1430: @destructor static function statidDtor() -:1431: { 374:1432: delete unique; 374:1433: } -:1434: -:1435: @constructor static function statidCtor() -:1436: { 374:1437: unique = (new TypeVoid).create(); 374:1438: } -:1439: -:1440: @constructor function create() -:1441: { 374:1442: this.kind = tkVoid; 374:1443: } -:1444: -:1445:protection (public) -:1446: -:1447: /// Returns: the unique instance -:1448: static function instance(): TypeVoid* -:1449: { 4090:1450: return unique; -:1451: } -:1452: 8:1453: @override function isVariableType(): bool { return false; } -:1454:} -:1455: -:1456:@unittest function testSingletonDtors() -:1457:{ -:1458: alias T = TypePointer; -:1459: -:1460: var T* tm1 = (new T).create(TypeS8.instance()); -:1461: var T* tm2 = (new T).create(TypeS8.instance()); -:1462: var T* tm3 = (new T).create(TypeS8.instance()); -:1463: var T* tm4 = (new T).create(TypeU8.instance()); -:1464: -:1465: assert(tm1 == tm2); -:1466: assert(tm1 != tm4); -:1467: -:1468: delete tm1; -:1469: delete tm2; -:1470: delete tm3; -:1471: delete tm4; -:1472:} -:1473: -:1474:@unittest function test1() -:1475:{ -:1476: assert(integerTypeFor(1) == TypeU8.instance()); -:1477: assert(integerTypeFor(256) == TypeU16.instance()); -:1478:} <<<<<< EOF # path=src/styx/ast/visitor.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/ast/visitor.sx -: 1:unit styx.ast.visitor; -: 2: -: 3:@private import -: 4: styx.session, -: 5: styx.token, -: 6: styx.ast.base, -: 7: styx.ast.declarations, -: 8: styx.ast.expressions, -: 9: styx.ast.statements, -: 10: styx.ast.types, -: 11: ; -: 12: -: 13:class AstVisitor -: 14:{ -: 15: alias error = Session.error; -: 16: alias warn = Session.warn; -: 17: -: 18: @inline function visitConcreteDeclaration(Declaration* d) -: 19: { 160258: 20: var Declaration** ad = &d; 160258: 21: switch d.kind do -: 22: { 1813: 23: on $alias do visitAliasDeclaration(*(ad:AliasDeclaration**)); 1083: 24: on $assert do visitStaticAssertDeclaration(*(ad:StaticAssertDeclaration**)); 5705: 25: on $class do visitClassDeclaration(*(ad:ClassDeclaration**)); 2139: 26: on $enum do visitEnumDeclaration(*(ad:EnumDeclaration**)); 1116: 27: on $import do visitImportDeclaration(*(ad:ImportDeclaration**)); 63: 28: on $label do visitLabelDeclaration(*(ad:LabelDeclaration**)); 266: 29: on $overload do visitOverloadDeclaration(*(ad:OverloadDeclaration**)); 1998: 30: on $protection do visitProtectionDeclaration(*(ad:ProtectionDeclaration**)); 5054: 31: on $struct do visitStructDeclaration(*(ad:StructDeclaration**)); 211: 32: on $union do visitUnionDeclaration(*(ad:UnionDeclaration**)); 1845: 33: on $unit do visitUnitDeclaration(*(ad:UnitDeclaration**)); 51623: 34: on $var do visitVariableDeclaration(*(ad:VariableDeclaration**)); 605: 35: on $version do visitVersionBlockDeclaration(*(ad:VersionBlockDeclaration**) ); 1: 36: on dkEnumMembr do visitEnumMember(*(ad:EnumMember**)); 25: 37: on generic do visitGenericParameter(*(ad:GenericParameter**)); 126: 38: on eopLambda do visitExpressionAlias(*(ad:ExpressionAlias**)); -: 39: on $function do -: 40: { 86584: 41: if !session.compileUnittest && d.getAtUnittest() do 2032: 42: return; 84551: 43: visitFunctionDeclaration(*(ad:FunctionDeclaration**)); -: 44: } -: 45: else do assert(0, tokenString[d.kind].ptr); -: 46: } 158224: 47: } -: 48: -: 49: @inline function visitConcreteExpression(Expression* e) -: 50: { 501690: 51: var Expression** ae = &e; 501690: 52: switch e.operator do -: 53: { 20345: 54: on equal .. lesserEqual do visitCmpExpression(*(ae:CmpExpression**)); 2838: 55: on plus do visitAddExpression(*(ae:AddExpression**)); 686: 56: on plusAss do visitAddAssignExpression(*(ae:AddAssignExpression**)); 3364: 57: on andAnd do visitAndAndExpression(*(ae:AndAndExpression**)); 80: 58: on amp do visitAndExpression(*(ae:AndExpression**)); 25: 59: on ampAss do visitAndAssignExpression(*(ae:AndAssignExpression**)); 1434: 60: on $apply do visitApplyExpression(*(ae:ApplyExpression**)); 1086: 61: on eopArray do visitArrayExpression(*(ae:ArrayExpression**)); 47: 62: on $asm do visitAsmExpression(*(ae:AsmExpression**)); 16198: 63: on ass do visitAssignExpression(*(ae:AssignExpression**)); 1984: 64: on eopAt do visitAtExpression(*(ae:AtExpression**)); 5745: 65: on $bool do visitBoolExpression(*(ae:BoolExpression**)); 33591: 66: on leftParen do visitCallExpression(*(ae:CallExpression**)); 19633: 67: on colon do visitCastExpression(*(ae:CastExpression**)); 2466: 68: on tidAss do visitConcatAssignExpression(*(ae:ConcatAssignExpression**)); 276: 69: on tidle do visitConcatExpression(*(ae:ConcatExpression**)); 1752: 70: on qmark do visitConditionalExpression(*(ae:ConditionalExpression**)); 549: 71: on eopDecl do visitDeclExpression(*(ae:DeclExpression**)); 440: 72: on $delete do visitDeleteExpression(*(ae:DeleteExpression**)); 4105: 73: on eopDeref do visitDerefExpression(*(ae:DerefExpression**)); 845: 74: on div do visitDivExpression(*(ae:DivExpression**)); 151: 75: on divAss do visitDivAssignExpression(*(ae:DivAssignExpression**)); 375: 76: on dollar do visitDollarExpression(*(ae:DollarExpression**)); 44559: 77: on dot do visitDotExpression(*(ae:DotExpression**)); 797: 78: on $echo do visitEchoExpression(*(ae:EchoExpression**)); 456: 79: on floatLiteral do visitFloatExpression(*(ae:FloatExpression**)); 190663: 80: on id do visitIdentExpression(*(ae:IdentExpression**)); 629: 81: on $in do visitInExpression(*(ae:InExpression**)); 4582: 82: on eopIndex do visitIndexExpression(*(ae:IndexExpression**)); 89384: 83: on intLiteral do visitIntegerExpression(*(ae:IntegerExpression**)); 30: 84: on lShift do visitLShiftExpression(*(ae:LShiftExpression**)); 11: 85: on lshiftAss do visitLShiftAssignExpression(*(ae:LShiftAssignExpression**)); 52: 86: on eopLambda do visitLambdaExpression(*(ae:LambdaExpression**)); 3171: 87: on eopLength do visitLengthExpression(*(ae:LengthExpression**)); 189: 88: on mod do visitModExpression(*(ae:ModExpression**)); 11: 89: on modAss do visitModAssignExpression(*(ae:ModAssignExpression**)); 1272: 90: on mul do visitMulExpression(*(ae:MulExpression**)); 30: 91: on mulAss do visitMulAssignExpression(*(ae:MulAssignExpression**)); 813: 92: on eopNeg do visitNegExpression(*(ae:NegExpression**)); 2228: 93: on $new do visitNewExpression(*(ae:NewExpression**)); 3419: 94: on not do visitNotExpression(*(ae:NotExpression**)); 4858: 95: on $null do visitNullExpression(*(ae:NullExpression**)); 42: 96: on eopPreTidle do visitOneCompExpression(*(ae:OneCompExpression**)); 164: 97: on pipe do visitOrExpression(*(ae:OrExpression**)); 26: 98: on pipeAss do visitOrAssignExpression(*(ae:OrAssignExpression**)); 1561: 99: on orOr do visitOrOrExpression(*(ae:OrOrExpression**)); 506:100: on optAccess do visitOptAccessExpression(*(ae:OptAccessExpression**)); 284:101: on optAss do visitOptAssignExpression(*(ae:OptAssignExpression**)); 2917:102: on eopPtr do visitPtrExpression(*(ae:PtrExpression**)); 225:103: on minMin do visitPostDecExpression(*(ae:PostDecExpression**)); 1407:104: on plusPlus do visitPostIncExpression(*(ae:PostIncExpression**)); 358:105: on eopPreDec do visitPreDecExpression(*(ae:PreDecExpression**)); 453:106: on eopPreInc do visitPreIncExpression(*(ae:PreIncExpression**)); 33:107: on rShift do visitRShiftExpression(*(ae:RShiftExpression**)); 11:108: on rshiftAss do visitRShiftAssignExpression(*(ae:RShiftAssignExpression**)); 1522:109: on dotDot do visitRangeExpression(*(ae:RangeExpression**)); 478:110: on eopRcaAssign do visitRcaAssignExpression(*(ae:RcaAssignExpression**)); 194:111: on eopRefCount do visitRefCountExpression(*(ae:RefCountExpression**)); 301:112: on eopSetLength do visitSetLengthExpression(*(ae:SetLengthExpression**)); 5133:113: on eopSlice do visitSliceExpression(*(ae:SliceExpression**)); 9707:114: on stringLiteral do visitStringExpression(*(ae:StringExpression**)); 1841:115: on minus do visitSubExpression(*(ae:SubExpression**)); 405:116: on minusAss do visitSubAssignExpression(*(ae:SubAssignExpression**)); 330:117: on $super do visitSuperExpression(*(ae:SuperExpression**)); 438:118: on rightParen do visitTupleExpression(*(ae:TupleExpression**)); 4246:119: on TokenType.$this do visitThisExpression(*(ae:ThisExpression**)); 3753:120: on eopType do visitTypeExpression(*(ae:TypeExpression**)); 148:121: on $version do visitVersionIdentExpression(*(ae:VersionIdentExpression**)); 18:122: on xor do visitXorExpression(*(ae:XorExpression**)); 20:123: on xorAss do visitXorAssignExpression(*(ae:XorAssignExpression**)); -:124: else do assert(0, tokenString[e.operator].ptr); -:125: } 501690:126: } -:127: -:128: @inline function visitConcreteStatement(Statement* s) -:129: { 215028:130: var Statement** as = &s; 215028:131: switch s.kind do -:132: { 8897:133: on $assert do visitAssertStatement(*(as:AssertStatement**)); 3359:134: on $break do visitBreakStatement(*(as:BreakStatement**)); 1071:135: on $continue do visitContinueStatement(*(as:ContinueStatement**)); 3060:136: on $foreach do visitForeachStatement(*(as:ForeachStatement**)); 42:137: on $goto do visitGotoStatement(*(as:GotoStatement**)); 24767:138: on $if do visitIfElseStatement(*(as:IfElseStatement**)); 26095:139: on $return do visitReturnStatement(*(as:ReturnStatement**)); 1430:140: on $switch do visitSwitchStatement(*(as:SwitchStatement**)); 144:141: on $version do visitVersionBlockStatement(*(as:VersionBlockStatement**)); 2313:142: on $while do visitWhileStatement(*(as:WhileStatement**)); 114:143: on $with do visitWithStatement(*(as:WithStatement**)); 56863:144: on semiColon do visitExpressionStatement(*(as:ExpressionStatement**)); 57135:145: on leftCurly do visitBlockStatement(*(as:BlockStatement**)); 39:146: on skBreakOn do visitBreakOnStatement(*(as:BreakOnStatement**)); 125:147: on skContinueOn do visitContinueOnStatement(*(as:ContinueOnStatement**)); 29574:148: on eopDecl do visitDeclarationStatement(*(as:DeclarationStatement**)); -:149: else do assert(0, tokenString[s.kind].ptr); -:150: } 215028:151: } -:152: -:153: @inline function visitConcreteType(Type* t) -:154: { -:155: alias E = ExtendedTokenType; 533309:156: var Type** att = &t; 533309:157: switch t.kind do -:158: { -:159: on $apply do assert(0); 213:160: on invalid do visitTypeError(*(att:TypeError**)); 3211:161: on $auto do visitTypeAuto(*(att:TypeAuto**)); 38011:162: on $class do visitTypeClass(*(att:TypeClass**)); 41:163: on $echo do visitTypeEcho(*(att:TypeEcho**)); 31:164: on leftSquare do visitTypeElements(*(att:TypeElements**)); 1383:165: on $enum do visitTypeEnum(*(att:TypeEnum**)); 6010:166: on $function do visitTypeFunction(*(att:TypeFunction**)); 107020:167: on id do visitTypeIdentifier(*(att:TypeIdentifier**)); 10421:168: on $struct do visitTypeStruct(*(att:TypeStruct**)); 36:169: on $union do visitTypeUnion(*(att:TypeUnion**)); 5:170: on $overload do visitTypeOverload(*(att:TypeOverload**)); 21:171: on dotDot do visitTypeRange(*(att:TypeRange**)); 16656:172: on $bool do visitTypeBool(*(att:TypeBool**)); 166:173: on $f32 do visitTypeF32(*(att:TypeF32**)); 465:174: on $f64 do visitTypeF64(*(att:TypeF64**)); 15680:175: on $s8 do visitTypeS8(*(att:TypeS8**)); 258:176: on $s16 do visitTypeS16(*(att:TypeS16**)); 6736:177: on $s32 do visitTypeS32(*(att:TypeS32**)); 1835:178: on $s64 do visitTypeS64(*(att:TypeS64**)); 66926:179: on $u8 do visitTypeU8(*(att:TypeU8**)); 1006:180: on $u16 do visitTypeU16(*(att:TypeU16**)); 14444:181: on $u32 do visitTypeU32(*(att:TypeU32**)); 15789:182: on $u64 do visitTypeU64(*(att:TypeU64**)); 158179:183: on mul do visitTypePointer(*(att:TypePointer**)); 90:184: on $null do visitTypeNull(*(att:TypeNull**)); 9093:185: on tkSlice do visitTypeSlice(*(att:TypeSlice**)); 10872:186: on tkSta do visitTypeStaticArray(*(att:TypeStaticArray**)); 711:187: on comma do visitTypeTuple(*(att:TypeTuple**)); 65:188: on tkUnamb do visitTypeUnambiguous(*(att:TypeUnambiguous**)); 38703:189: on tkVoid do visitTypeVoid(*(att:TypeVoid**)); 476:190: on tkEnumSet do visitTypeEnumSet(*(att:TypeEnumSet**)); 8751:191: on tkRca do visitTypeRcArray(*(att:TypeRcArray**)); 5:192: on rightSquare do visitTypeEmptyArray(*(att:TypeEmptyArray**)); -:193: else do assert(0, tokenString[t.kind].ptr); -:194: } 533309:195: } -:196: -:197: @virtual function visitAggregate(AggregateDeclaration* node){ assert(0); } 512:198: @virtual function visitAddAssignExpression(AddAssignExpression* node){ node.accept(this); } 1966:199: @virtual function visitAddExpression(AddExpression* node){ node.accept(this); } 2012:200: @virtual function visitAndAndExpression(AndAndExpression* node){ node.accept(this); } 50:201: @virtual function visitAliasDeclaration(AliasDeclaration* node){ node.accept(this); } 18:202: @virtual function visitAndAssignExpression(AndAssignExpression* node){ node.accept(this); } 50:203: @virtual function visitAndExpression(AndExpression* node){ node.accept(this); } 770:204: @virtual function visitApplyExpression(ApplyExpression* node){ node.accept(this); } 702:205: @virtual function visitArrayExpression(ArrayExpression* node){ node.accept(this); } 10874:206: @virtual function visitAssertStatement(AssertStatement* node){ node.accept(this); } 10982:207: @virtual function visitAssignExpression(AssignExpression* node){ node.accept(this); } 32:208: @virtual function visitAsmExpression(AsmExpression* node){ node.accept(this); } 866:209: @virtual function visitAtExpression(AtExpression* node){ node.accept(this); } 2976:210: @virtual function visitAttribute(Attribute* node){ node.accept(this); } 14852:211: @virtual function visitAttributes(Attributes* node){ node.accept(this); } -:212: @virtual function visitBinaryExpression(BinaryExpression* node){ assert(0); } 26730:213: @virtual function visitBlockStatement(BlockStatement* node){ node.accept(this); } 3182:214: @virtual function visitBoolExpression(BoolExpression* node){ node.accept(this); } 48:215: @virtual function visitBreakOnStatement(BreakOnStatement* node){ node.accept(this); } 4088:216: @virtual function visitBreakStatement(BreakStatement* node){ node.accept(this); } 21812:217: @virtual function visitCallExpression(CallExpression* node){ node.accept(this); } 7136:218: @virtual function visitCastExpression(CastExpression* node){ node.accept(this); } 724:219: @virtual function visitClassDeclaration(ClassDeclaration* node){ node.accept(this); } 8910:220: @virtual function visitCmpExpression(CmpExpression* node){ node.accept(this); } 1696:221: @virtual function visitConcatAssignExpression(ConcatAssignExpression* node){ node.accept(this); } 188:222: @virtual function visitConcatExpression(ConcatExpression* node){ node.accept(this); } 1240:223: @virtual function visitConditionalExpression(ConditionalExpression* node){ node.accept(this); } 1306:224: @virtual function visitContinueStatement(ContinueStatement* node){ node.accept(this); } 156:225: @virtual function visitContinueOnStatement(ContinueOnStatement* node){ node.accept(this); } 196292:226: @virtual function visitDeclaration(Declaration* node){ visitConcreteDeclaration(node); } 58772:227: @virtual function visitDeclarationStatement(DeclarationStatement* node){ node.accept(this); } 28344:228: @virtual function visitDeclarations(Declarations* node){ node.accept(this); } 14:229: @virtual function visitDeclExpression(DeclExpression* node) { node.accept(this); } 278:230: @virtual function visitDeleteExpression(DeleteExpression* node) { node.accept(this); } 2744:231: @virtual function visitDerefExpression(DerefExpression* node) { node.accept(this); } 104:232: @virtual function visitDivAssignExpression(DivAssignExpression* node){ node.accept(this); } 578:233: @virtual function visitDivExpression(DivExpression* node){ node.accept(this); } 256:234: @virtual function visitDollarExpression(DollarExpression* node) { node.accept(this); } 33338:235: @virtual function visitDotExpression(DotExpression* node) { node.accept(this); } 642:236: @virtual function visitEchoExpression(EchoExpression* node){ node.accept(this); } 1580:237: @virtual function visitEnumDeclaration(EnumDeclaration* node){ node.accept(this); } 3768:238: @virtual function visitEnumMember(EnumMember* node){ node.accept(this); } 96:239: @virtual function visitExpressionAlias(ExpressionAlias* node){ node.accept(this); } 304620:240: @virtual function visitExpression(Expression* node){ visitConcreteExpression(node); } 69170:241: @virtual function visitExpressionStatement(ExpressionStatement* node){ node.accept(this); } 250:242: @virtual function visitFloatExpression(FloatExpression* node){ node.accept(this); } 2556:243: @virtual function visitForeachStatement(ForeachStatement* node){ node.accept(this); } 11130:244: @virtual function visitFunctionDeclaration(FunctionDeclaration* node){ node.accept(this); } 1550:245: @virtual function visitGenericParameter(GenericParameter* node){ } 2696:246: @virtual function visitGenericParameters(GenericParameters* node){ node.accept(this); } 52:247: @virtual function visitGotoStatement(GotoStatement* node){ node.accept(this); } 19696:248: @virtual function visitIfElseStatement(IfElseStatement* node){ node.accept(this); } 374:249: @virtual function visitImportDeclaration(ImportDeclaration* node){ node.accept(this); } 129072:250: @virtual function visitIdentExpression(IdentExpression* node) { node.accept(this); } 372:251: @virtual function visitInExpression(InExpression* node) { node.accept(this); } 2918:252: @virtual function visitIndexExpression(IndexExpression* node) { node.accept(this); } 21804:253: @virtual function visitIntegerExpression(IntegerExpression* node){ node.accept(this); } 70:254: @virtual function visitLabelDeclaration(LabelDeclaration* node){ node.accept(this); } 8:255: @virtual function visitLShiftAssignExpression(LShiftAssignExpression* node){ node.accept(this); } 18:256: @virtual function visitLShiftExpression(LShiftExpression* node){ node.accept(this); } 50:257: @virtual function visitLambdaExpression(LambdaExpression* node){ node.accept(this); } 62:258: @virtual function visitLengthExpression(LengthExpression* node){ node.accept(this); } 8:259: @virtual function visitModAssignExpression(ModAssignExpression* node){ node.accept(this); } 126:260: @virtual function visitModExpression(ModExpression* node){ node.accept(this); } 20:261: @virtual function visitMulAssignExpression(MulAssignExpression* node){ node.accept(this); } 926:262: @virtual function visitMulExpression(MulExpression* node){ node.accept(this); } 554:263: @virtual function visitNegExpression(NegExpression* node) { node.accept(this); } 1584:264: @virtual function visitNewExpression(NewExpression* node) { node.accept(this); } -:265: @virtual function visitAstNode(AstNode* node){ assert(0); } 2474:266: @virtual function visitNotExpression(NotExpression* node) { node.accept(this); } 2184:267: @virtual function visitNullExpression(NullExpression* node) { node.accept(this); } 28:268: @virtual function visitOneCompExpression(OneCompExpression* node){ node.accept(this); } 9326:269: @virtual function visitOnMatchStatement(OnMatchStatement* node){ node.accept(this); } 332:270: @virtual function visitOptAccessExpression(OptAccessExpression* node){ node.accept(this); } 174:271: @virtual function visitOptAssignExpression(OptAssignExpression* node){ node.accept(this); } 18:272: @virtual function visitOrAssignExpression(OrAssignExpression* node){ node.accept(this); } 110:273: @virtual function visitOrExpression(OrExpression* node){ node.accept(this); } 984:274: @virtual function visitOrOrExpression(OrOrExpression* node){ node.accept(this); } 128:275: @virtual function visitOverloadDeclaration(OverloadDeclaration* node){ node.accept(this); } 156:276: @virtual function visitPostDecExpression(PostDecExpression* node){ node.accept(this); } 1050:277: @virtual function visitPostIncExpression(PostIncExpression* node){ node.accept(this); } 304:278: @virtual function visitPreDecExpression(PreDecExpression* node){ node.accept(this); } 316:279: @virtual function visitPreIncExpression(PreIncExpression* node){ node.accept(this); } 3652:280: @virtual function visitProtectionDeclaration(ProtectionDeclaration* node){ node.accept(this); } 30:281: @virtual function visitPtrExpression(PtrExpression* node){ node.accept(this); } 8:282: @virtual function visitRShiftAssignExpression(RShiftAssignExpression* node){ node.accept(this); } 20:283: @virtual function visitRShiftExpression(RShiftExpression* node){ node.accept(this); } 2048:284: @virtual function visitRangeExpression(RangeExpression* node){ node.accept(this); } 6:285: @virtual function visitRcaAssignExpression(RcaAssignExpression* node){ node.accept(this); } 8:286: @virtual function visitRefCountExpression(RefCountExpression* node){ } 28518:287: @virtual function visitReturnStatement(ReturnStatement* node){ node.accept(this); } 4:288: @virtual function visitSetLengthExpression(SetLengthExpression* node){ node.accept(this); } 1650:289: @virtual function visitSliceExpression(SliceExpression* node){ node.accept(this); } 408676:290: @virtual function visitStatement(Statement* node){ visitConcreteStatement(node); } 1556:291: @virtual function visitStaticAssertDeclaration(StaticAssertDeclaration* node){ node.accept(this); } 6540:292: @virtual function visitStringExpression(StringExpression* node){ node.accept(this); } 500:293: @virtual function visitStructDeclaration(StructDeclaration* node){ node.accept(this); } 280:294: @virtual function visitSubAssignExpression(SubAssignExpression* node){ node.accept(this); } 1294:295: @virtual function visitSubExpression(SubExpression* node){ node.accept(this); } 222:296: @virtual function visitSuperExpression(SuperExpression* node){ node.accept(this); } 1760:297: @virtual function visitSwitchStatement(SwitchStatement* node){ node.accept(this); } 1424:298: @virtual function visitThisExpression(ThisExpression* node){ node.accept(this); } 274:299: @virtual function visitTupleExpression(TupleExpression* node){ node.accept(this); } 0:300: @virtual function visitTypeAppliedGeneric(TypeAppliedGeneric* node){ node.accept(this); } 6068:301: @virtual function visitTypeAuto(TypeAuto* node){ node.accept(this); } 2686:302: @virtual function visitTypeBool(TypeBool* node){ node.accept(this); } 666:303: @virtual function visitTypeClass(TypeClass* node){ node.accept(this); } 18:304: @virtual function visitTypeElements(TypeElements* node){ node.accept(this); } 40:305: @virtual function visitTypeEcho(TypeEcho* node){ node.accept(this); } 4:306: @virtual function visitTypeEmptyArray(TypeEmptyArray* node){ node.accept(this); } 142:307: @virtual function visitTypeEnum(TypeEnum* node){ node.accept(this); } 84:308: @virtual function visitTypeEnumSet(TypeEnumSet* node){ node.accept(this); } 1180:309: @virtual function visitTypeExpression(TypeExpression* node){ node.accept(this); } 190:310: @virtual function visitTypeError(TypeError* node){ node.accept(this); } 126:311: @virtual function visitTypeF32(TypeF32* node){ node.accept(this); } 310:312: @virtual function visitTypeF64(TypeF64* node){ node.accept(this); } 24:313: @virtual function visitTypeFunction(TypeFunction* node){ node.accept(this); } 23940:314: @virtual function visitTypeIdentifier(TypeIdentifier* node){ node.accept(this); } 94638:315: @virtual function visitType(Type* node){ visitConcreteType(node); } 0:316: @virtual function visitTypeNull(TypeNull* node){ } 0:317: @virtual function visitTypeOverload(TypeOverload* node){ node.accept(this); } 26314:318: @virtual function visitTypePointer(TypePointer* node){ node.accept(this); } 4:319: @virtual function visitTypeRange(TypeRange* node){ node.accept(this); } 2992:320: @virtual function visitTypeRcArray(TypeRcArray* node){ node.accept(this); } 212:321: @virtual function visitTypeTuple(TypeTuple* node){ node.accept(this); } 240:322: @virtual function visitTypeS16(TypeS16* node){ node.accept(this); } 6556:323: @virtual function visitTypeS32(TypeS32* node){ node.accept(this); } 1256:324: @virtual function visitTypeS64(TypeS64* node){ node.accept(this); } 6228:325: @virtual function visitTypeS8(TypeS8* node){ node.accept(this); } 1664:326: @virtual function visitTypeSlice(TypeSlice* node){ node.accept(this); } 24:327: @virtual function visitTypeStruct(TypeStruct* node){ node.accept(this); } 1198:328: @virtual function visitTypeStaticArray(TypeStaticArray* node){ node.accept(this); } 554:329: @virtual function visitTypeU16(TypeU16* node){ node.accept(this); } 3910:330: @virtual function visitTypeU32(TypeU32* node){ node.accept(this); } 8232:331: @virtual function visitTypeU64(TypeU64* node){ node.accept(this); } 6552:332: @virtual function visitTypeU8(TypeU8* node){ node.accept(this); } 0:333: @virtual function visitTypeUnion(TypeUnion* node){ node.accept(this); } 6108:334: @virtual function visitTypeVoid(TypeVoid* node){ node.accept(this); } 1888:335: @virtual function visitUnitDeclaration(UnitDeclaration* node){ node.accept(this); } 22:336: @virtual function visitUnionDeclaration(UnionDeclaration* node){ node.accept(this); } 64:337: @virtual function visitTypeUnambiguous(TypeUnambiguous* node){ node.accept(this); } 15910:338: @virtual function visitVariableDeclaration(VariableDeclaration* node){ node.accept(this); } 660:339: @virtual function visitVersionBlockDeclaration(VersionBlockDeclaration* node){ node.accept(this); } 126:340: @virtual function visitVersionBlockStatement(VersionBlockStatement* node){ node.accept(this); } 24:341: @virtual function visitVersionIdentExpression(VersionIdentExpression* node){ node.accept(this); } 1858:342: @virtual function visitWhileStatement(WhileStatement* node){ node.accept(this); } 96:343: @virtual function visitWithStatement(WithStatement* node){ node.accept(this); } 14:344: @virtual function visitXorAssignExpression(XorAssignExpression* node){ node.accept(this); } 10:345: @virtual function visitXorExpression(XorExpression* node){ node.accept(this); } -:346:} <<<<<< EOF # path=src/styx/backend/irgen.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/backend/irgen.sx -: 1:unit styx.backend.irgen; -: 2: -: 3:@private import -: 4: algorithms, -: 5: styx.ast.base, -: 6: styx.ast.declarations, -: 7: styx.ast.expressions, -: 8: styx.ast.formatter, -: 9: styx.ast.statements, -: 10: styx.ast.types, -: 11: styx.ast.visitor, -: 12: styx.backend.llvm, -: 13: styx.position, -: 14: styx.session, -: 15: styx.symbol, -: 16: styx.token, -: 17: system, -: 18: ; -: 19: -: 20:protection (private) -: 21: -: 22:/// IR for the OptAccessExpression -: 23:struct OptExpIr -: 24:{ -: 25: /// The block where the null result is generated -: 26: @noinit var LLVMBasicBlockRef skippedValueBr; -: 27: /// The null result -: 28: @noinit var LLVMValueRef skippedValue; -: 29: /// The block where the phi is located -: 30: @noinit var LLVMBasicBlockRef phiBr; -: 31: /// IF something has to be selected -: 32: @noinit var bool isPhiNeeded; -: 33: /// -: 34: @constructor function create(const LLVMBasicBlockRef skippedValueBr; const LLVMValueRef skippedValue; const LLVMBasicBlockRef phiBr; const bool isPhiNeeded) -: 35: { 158: 36: this.skippedValueBr = skippedValueBr; 158: 37: this.skippedValue = skippedValue; 158: 38: this.phiBr = phiBr; 158: 39: this.isPhiNeeded = isPhiNeeded; 158: 40: } -: 41:} -: 42: -: 43:/// IR that cache the condition for the CondExp shorthand syntax -: 44:struct CmpExpLeftIr -: 45:{ -: 46: /// -: 47: @noinit var LLVMValueRef asLvalue; -: 48: /// -: 49: @noinit var LLVMValueRef asRvalue; -: 50: /// -: 51: @constructor function create(const LLVMValueRef asLvalue; const LLVMValueRef asRvalue) -: 52: { 6534: 53: this.asLvalue = asLvalue; 6534: 54: this.asRvalue = asRvalue; 6534: 55: } -: 56:} -: 57: -: 58:/// IR for ForeachStatement and WhileStatement -: 59:struct LoopBlockRefIr -: 60:{ -: 61: /// The `continue` destination -: 62: @noinit var LLVMBasicBlockRef continueBr; -: 63: /// The `break` destination -: 64: @noinit var LLVMBasicBlockRef breakBr; -: 65: /// -: 66: @constructor function create(const LLVMBasicBlockRef continueBr; const LLVMBasicBlockRef breakBr) -: 67: { 959: 68: this.continueBr = continueBr; 959: 69: this.breakBr = breakBr; 959: 70: } -: 71:} -: 72: -: 73:/// IR for Type -: 74:struct TypeIr -: 75:{ -: 76: /// The type IR -: 77: @noinit var LLVMTypeRef tir; -: 78: /// The default init IR -: 79: @noinit var LLVMValueRef iir; -: 80: /// Type ir of a pointer to a tir -: 81: @noinit var LLVMTypeRef pir; -: 82: /// -: 83: @constructor function create(const LLVMTypeRef tir; const LLVMValueRef iir) -: 84: { 106570: 85: this.tir = tir; 106570: 86: this.iir = iir; 106570: 87: this.pir = LLVMPointerType(tir, 0); 106570: 88: } -: 89:} -: 90: -: 91:/// Returns: the IR for a Type -: 92:function getTypeIr(Type* node): LLVMTypeRef -: 93:{ 410864: 94: node = node.resolved(); 410864: 95: assert(node.ir); 410864: 96: return (node.ir:TypeIr*).tir; -: 97:} -: 98: -: 99:/// Returns: the IR for the TypePointer of a particular Type -: 100:function getPointerTypeIr(Type* node): LLVMTypeRef -: 101:{ 20085: 102: node = node.resolved(); 20085: 103: assert(node.ir); 20085: 104: return (node.ir:TypeIr*).pir; -: 105:} -: 106: -: 107:/// Returns: the IR of the default value of a Type -: 108:function getTypeInitIr(Type* node): LLVMValueRef -: 109:{ 48291: 110: node = node.resolved(); 48291: 111: assert(node.ir); 48291: 112: return (node.ir:TypeIr*).iir; -: 113:} -: 114: -: 115:function setTypeIr(const Type* node; const LLVMTypeRef typeIr; const LLVMValueRef initIr) -: 116:{ 106570: 117: node.ir = (new TypeIr).create(typeIr, initIr):u8*; 106570: 118:} -: 119: -: 120:/// Returns: the DI for a Type -: 121:function getTypeDi(const Type* node): LLVMMetadataRef -: 122:{ 81576: 123: return node.dbgIr:LLVMMetadataRef; -: 124:} -: 125: -: 126:function nodeIRtoValueRef(const AstNode* node): LLVMValueRef -: 127:{ 103318: 128: return node.ir:LLVMValueRef; -: 129:} -: 130: -: 131:function nodeIRtoBlockRef(const AstNode* node): LLVMBasicBlockRef -: 132:{ 34: 133: return node.ir:LLVMBasicBlockRef; -: 134:} -: 135: -: 136:/// The type of a pointer to an instruction builder function that builds a binary expression -: 137:alias BinOpFun = (function(InstrBuilder* this; LLVMValueRef v1; LLVMValueRef v2; s8* name = ""): LLVMValueRef)*; -: 138: -: 139:/// Manage the optional data that LLVM takes to give error messages. -: 140:function displayError(var s8* c): bool -: 141:{ -: 142: var bool result; 554: 143: if c do -: 144: { 1: 145: printf("%s\n", c); 1: 146: LLVMDisposeMessage(c); 1: 147: c = null; 1: 148: result = true; -: 149: } 554: 150: return result; -: 151:} -: 152: -: 153:function optimize(const LLVMModuleRef m): bool -: 154:{ 1: 155: var auto pmb = (new PassManagerBuilder).create(); 1: 156: pmb.setOptLevel(session.optLevel); 1: 157: pmb.setSizeLevel(0); 1: 158: pmb.setInlineThresh(255); -: 159: 1: 160: var auto pm = (new PassManager).create(m); -: 161: 1: 162: pmb.addDefaultFunctionPasses(pm); 1: 163: pm.runFunctions(); -: 164: 1: 165: pmb.addDefaultModulePasses(pm); 1: 166: pm.runModule(); -: 167: 1: 168: delete pmb; 1: 169: delete pm; -: 170: 1: 171: return true; -: 172:} -: 173: -: 174:function outputIR(LLVMModuleRef moduleRef; s8[] baseName): bool -: 175:{ -: 176: @foreign function LLVMPrintModuleToFile(LLVMModuleRef m; s8* fname; s8** errorMsg): bool; -: 177: -: 178: var s8* errors; 7: 179: const auto result = LLVMPrintModuleToFile(moduleRef, (baseName ~ ".ll\0").ptr, &errors); 7: 180: displayError(errors); 7: 181: return result == 0; -: 182:} -: 183: -: 184:function outputBC(LLVMModuleRef moduleRef; s8[] baseName): bool -: 185:{ -: 186: @foreign function LLVMWriteBitcodeToMemoryBuffer(LLVMModuleRef m): LLVMMemoryBufferRef; -: 187: @foreign function LLVMGetBufferStart(LLVMMemoryBufferRef buff): s8*; -: 188: @foreign function LLVMGetBufferSize(LLVMMemoryBufferRef buff): usize; -: 189: 1: 190: var auto buff = LLVMWriteBitcodeToMemoryBuffer(moduleRef); 1: 191: system.fileWrite(baseName ~ ".bc\0", LLVMGetBufferStart(buff)[0 .. LLVMGetBufferSize(buff)]); 1: 192: return true; -: 193:} -: 194: -: 195:function outputOBJ(LLVMModuleRef moduleRef; s8[] baseName; bool asAsm): bool -: 196:{ -: 197: @foreign function LLVMGetTargetFromName(s8* t): LLVMTargetRef; -: 198: @foreign function LLVMGetTargetFromTriple(s8* t; LLVMTargetRef* tr; s8** error): s32; -: 199: @foreign function LLVMCreateTargetMachine(LLVMTargetRef T; const s8* Triple; const s8* CPU; const s8* Features; LLVMCodeGenOptLevel Level; LLVMRelocMode Reloc; LLVMCodeModel CodeModel): LLVMTargetMachineRef; -: 200: @foreign function LLVMTargetMachineEmitToFile(LLVMTargetMachineRef tm; LLVMModuleRef m; s8* fname; LLVMCodeGenFileType cgft; s8** error): s32; -: 201: @foreign function LLVMGetHostCPUName(): s8*; -: 202: @foreign function LLVMGetHostCPUFeatures(): s8*; -: 203: @foreign function LLVMNormalizeTargetTriple(const s8* triple): s8*; -: 204: -: 205: var s8* errors; -: 206: var bool fail; 273: 207: var s8[] ext = asAsm? ".s"[] else ".o"[] ; 273: 208: var s8[] fname = baseName ~ ext ~ "\0"; 273: 209: var s8[] target = MachineTarget.getTriple(); 273: 210: var s8* normt = LLVMNormalizeTargetTriple(target.ptr); 273: 211: var auto tr = LLVMGetTargetFromName(normt); 273: 212: var s8* cpu = null; 273: 213: var s8* features = MachineTarget.getFeatures().ptr; 273: 214: var auto rm = LLVMRelocMode.PIC; 273: 215: var auto cgopt = session.optLevel:LLVMCodeGenOptLevel; 273: 216: var auto cm = LLVMCodeModel.Default; // realted to -Os / -Oz 273: 217: var auto cgtype = asAsm ? LLVMCodeGenFileType.AssemblyFile else LLVMCodeGenFileType.ObjectFile; -: 218: var LLVMTargetMachineRef tm; -: 219: 273: 220: LLVMGetTargetFromTriple(normt, &tr, &errors); 273: 221: fail |= displayError(errors); 273: 222: if !fail do 273: 223: tm = LLVMCreateTargetMachine(tr, normt, cpu, features, cgopt, rm, cm); 273: 224: fail |= tm == null; 273: 225: if !fail do 273: 226: LLVMTargetMachineEmitToFile(tm, moduleRef, fname.ptr, cgtype, &errors); 273: 227: fail |= displayError(errors); -: 228: 273: 229: if !asAsm && !fail do -: 230: { -: 231: // workaround problem of dead memory 272: 232: var s8[+] n = fname; 272: 233: n.incref; -: 234: 272: 235: session.objects ~= n[]; -: 236: } -: 237: 273: 238: return !fail; -: 239:} -: 240: -: 241:function getLLVMAttribute(LLVMContextRef ctxt; s8[] s; u32 userTag = 0): LLVMAttributeRef -: 242:{ -: 243: @foreign function LLVMGetEnumAttributeKindForName(s8* name; usize nameLen): u32; -: 244: @foreign function LLVMCreateEnumAttribute(LLVMContextRef ctxt; u32 id; u32 value): LLVMAttributeRef; -: 245: 391: 246: const u32 id = LLVMGetEnumAttributeKindForName(s.ptr, s.length); 391: 247: return LLVMCreateEnumAttribute(ctxt, id, userTag); -: 248:} -: 249: -: 250:struct DeclModuleInfo -: 251:{ -: 252: @constructor function create(const bool isImported; const bool isVisited) -: 253: { 290613: 254: this.isImported = isImported; 290613: 255: this.isVisited = isVisited; 290613: 256: } -: 257: @noinit var bool isImported; -: 258: @noinit var bool isVisited; -: 259:} -: 260: -: 261:enum TSliceLayout -: 262:{ -: 263: lenIdx = 0, -: 264: ptrIdx = 1, -: 265:} -: 266: -: 267:struct FuncTyAndPtr -: 268:{ -: 269: var LLVMTypeRef type; -: 270: var LLVMValueRef func; -: 271:} -: 272: -: 273:@public @final class LLVMIrGen : AstVisitor -: 274:{ -: 275: var bool diGenerate; -: 276: var bool successFlag; -: 277: -: 278: // contain the expression IR after a visitXXX() -: 279: var LLVMValueRef exp; -: 280: -: 281: // contexts -: 282: var UnitDeclaration* unitNode; -: 283: var LLVMModuleRef unitIr; -: 284: var LLVMContextRef ctxt; -: 285: var InstrBuilder* instrBuilder; -: 286: var LLVMMetadataRef diScope; -: 287: var s8[] moduleString; -: 288: -: 289: // debug info -: 290: var DIBuilder* diBuilder; -: 291: var LLVMMetadataRef diUnitRef; -: 292: var LLVMMetadataRef rcaTypeDi; -: 293: -: 294: // coverage -: 295: var bool doCover; -: 296: var LLVMValueRef[+] coverArrayInit; -: 297: var LLVMValueRef coverArrayIr; -: 298: var LLVMValueRef coverageFinalizer; -: 299: -: 300: // commonly used constants -: 301: var LLVMValueRef zero32; -: 302: var LLVMValueRef zero8; -: 303: var LLVMValueRef one32; -: 304: var LLVMValueRef minusOne32; -: 305: var LLVMValueRef zerosize; -: 306: var LLVMValueRef nullPtr; -: 307: var LLVMValueRef onesize; -: 308: var LLVMTypeRef rcaType; -: 309: var LLVMTypeRef rcaTypePointee; -: 310: -: 311: // front-end checks but does not add the missing `this.` -: 312: // this value is cached on function member entry (1st param value) -: 313: var LLVMValueRef thisExp; -: 314: -: 315: // current stuff -: 316: var LLVMValueRef currentFunction; -: 317: var LLVMValueRef currentSwitch; -: 318: var LLVMTypeRef currentAggregateType; -: 319: var LLVMBasicBlockRef currentBlock; -: 320: var LLVMInlineAsmDialect currentAsmDialect; -: 321: var bool isRtlRootUnit; -: 322: var LLVMValueRef currentArrayExp; -: 323: -: 324: // escapes -: 325: var LLVMValueRef currentEscapes; -: 326: var bool inNestedFunc; -: 327: var LLVMValueRef escapeFrontVar; -: 328: -: 329: // static ctor/dtor stuff -: 330: var FunctionDeclaration*[+] staticCtors; -: 331: var FunctionDeclaration*[+] staticDtors; -: 332: var LLVMTypeRef staticCtorDtorEntryType; -: 333: -: 334: // cache LLVM atrributes -: 335: var LLVMAttributeRef attrOptNone; -: 336: var LLVMAttributeRef attrInlineMaybe; -: 337: var LLVMAttributeRef attrInlineAlways; -: 338: var LLVMAttributeRef attrInlineNo; -: 339: var LLVMAttributeRef attrNoReturn; -: 340: -: 341: // cache the IR to call some libc funcs, (libc_xxxx funcs) -: 342: var FuncTyAndPtr fflushRef; -: 343: var FuncTyAndPtr memcmpRef; -: 344: var FuncTyAndPtr printfRef; -: 345: var FuncTyAndPtr reallocRef; -: 346: -: 347: // cache the IR to call LLVM intrinsics, (llvm_xxxx funcs) -: 348: var FuncTyAndPtr dbgDeclareRef; -: 349: var FuncTyAndPtr trapRef; -: 350: -: 351: // cache the IR to call the RTL functions, (rtl_xxxx funcs) -: 352: var FuncTyAndPtr dynCastRef; -: 353: var FuncTyAndPtr rcaAppendRef; -: 354: var FuncTyAndPtr rcaBeforeReturnRef; -: 355: var FuncTyAndPtr rcaDecRefCountRef; -: 356: var FuncTyAndPtr rcaDecRefCountNestRef; -: 357: var FuncTyAndPtr rcaDupRef; -: 358: var FuncTyAndPtr rcaElemDtorRef; -: 359: var FuncTyAndPtr rcaFromSliceRef; -: 360: var FuncTyAndPtr rcaGetLengthRef; -: 361: var FuncTyAndPtr rcaIncRefCountRef; -: 362: var FuncTyAndPtr rcaPtrRef; -: 363: var FuncTyAndPtr rcaRefCountRef; -: 364: var FuncTyAndPtr rcaSetLengthRef; -: 365: var FuncTyAndPtr finalizeCovRef; -: 366: -: 367: // the printf() specifiers used by the `--check` code on failure -: 368: var LLVMValueRef abstractSpecifier; -: 369: var LLVMValueRef nullStructGepSpecifier; -: 370: var LLVMValueRef assertSpecifier; -: 371: var LLVMValueRef nullthisSpecifier; -: 372: var LLVMValueRef boundsSpecifier; -: 373: var LLVMValueRef switchSpecifier; -: 374: var LLVMValueRef sliceHiLowSpecifier; -: 375: var LLVMValueRef sliceAssSpecifier; -: 376: -: 377: // to cleanup some fields after unit completed -: 378: var Appender:[AggregateDeclaration*, 128] vtableOwners; -: 379: var Appender:[VariableDeclaration*, 8] copiedToLocal; -: 380: var Appender:[AstNode*, 512] visited; -: 381: -: 382: // so that func bodies can be processed once all variables are known -: 383: var Appender:[FunctionDeclaration*, 512] functions; -: 384: var Appender:[FunctionDeclaration*, 512] functions2; -: 385: var u8 pass; -: 386: -: 387: /// If `type` is a `TypeAggregate`, destroy the lvalue instance given by `thisArg` -: 388: function aggregateDtor(Type* type; LLVMValueRef thisArg; AstNode* diLoc) -: 389: { 5430: 390: var auto ta = asTypeAggregate(type); 10631: 391: if !ta do return; 229: 392: var auto dtor = ta.declaration.defaultDtor; 391: 393: if !dtor do return; 76: 394: if !dtor.ir do visitFunctionDeclaration(dtor); 67: 395: var auto callee = nodeIRtoValueRef(dtor); 67: 396: if dtor.virtualIndex != -1 do -: 397: { 5: 398: var auto vtty = ta.declaration.vtableVar.type; 5: 399: var auto ftpe = LLVMTypeOf(callee); 5: 400: var auto vidx = constBuilder.int(getTypeIr(TypeU32.instance()), dtor.virtualIndex + 1, false); 5: 401: callee = instrBuilder.structGep(getTypeIr(ta), thisArg, 0); 5: 402: callee = instrBuilder.load(getTypeIr(vtty), callee); 5: 403: callee = instrBuilder.gep(getTypeIr(asTypePointer(vtty).modified), callee, [zero32, vidx]); 5: 404: callee = instrBuilder.load(ftpe, callee); -: 405: } 67: 406: var auto e = instrBuilder.call(getTypeIr(dtor.asTypeDeclared), callee, [thisArg]); 67: 407: instructionDi(diLoc, e); 67: 408: } -: 409: -: 410: // subroutine used with `--check=thiscalls` and `--check=dotvars` -: 411: function checkNull(var Position errorPos; LLVMValueRef maybeNull; LLVMValueRef specifier) -: 412: { 10262: 413: var auto passBr = instrBuilder.appendBasicBlock(currentFunction); 10262: 414: var auto failBr = instrBuilder.appendBasicBlock(currentFunction); -: 415: 10262: 416: var auto c = instrBuilder.icmp(LLVMIntPredicate.EQ, maybeNull, nullPtr); 10262: 417: instrBuilder.condBr(c, failBr, passBr); -: 418: 10262: 419: startBlock(failBr); 10262: 420: var LLVMValueRef[2] lineCol = getLineCol(errorPos); 10262: 421: generateCheckFail([specifier, lineCol[0], lineCol[1]]); 10262: 422: startBlock(passBr); 10262: 423: } -: 424: -: 425: /** -: 426: * Allows to take the address of a "passed-by-value" parameter . -: 427: * -: 428: * This creates a temporary, put the IR of the temporary on the VarDecl and -: 429: * truncate the VarDecl so that it looks like a local variable and not a parameter*/ -: 430: function copyParameterToReferencableLocal(VariableDeclaration* node) -: 431: { 5936: 432: if node.isVar() || isImmediate in node.flags do 1471: 433: return; 4465: 434: node.context = VariableDeclarationContext.default; 4465: 435: node.flags = 0; 4465: 436: var auto v = instrBuilder.alloca(getTypeIr(node.type)); 4465: 437: node.ir = v:u8*; 4465: 438: instrBuilder.store(LLVMGetParam(currentFunction, node.index), v); 4465: 439: copiedToLocal.append(node); 4465: 440: } -: 441: -: 442: function coverageRtlFinalizer() -: 443: { 10: 444: const auto f = rtl_finalizeCovRef(); 10: 445: const auto t = LLVMFunctionType(getTypeIr(TypeVoid.instance()), null, 0, false); 10: 446: coverageFinalizer = LLVMAddFunction(unitIr, (moduleString ~ ".__covFinalize\0").ptr, t); -: 447: 10: 448: var LLVMBasicBlockRef entry = instrBuilder.appendBasicBlock(coverageFinalizer, "entry"); 10: 449: instrBuilder.positionAtEnd(entry); 10: 450: const auto fname = unitNode.filename.absolutePath(); 10: 451: const auto a = instrBuilder.gep(getTypeIr(unitNode.coverData.type), coverArrayIr, [zero32, zero32]); 10: 452: const auto fname1 = instrBuilder.globalStringPtr(fname ~ "\0"); 10: 453: const auto fname2 = instrBuilder.globalStringPtr(fname.setExtension(".gcov\0")); 10: 454: const auto len = constBuilder.int(getTypeIr(TypeUSize()), unitNode.stopPos.line, false); 10: 455: instrBuilder.call(f.tupleof, [a, len, fname1, fname2]); 10: 456: instrBuilder.retVoid(); 10: 457: } -: 458: -: 459: function cover(var Position pos) -: 460: { -: 461: // this can happen because of generic arguments, -: 462: // for example the CondExp will use the elseExp.startPos, but -: 463: // that elseExp can come from a foreign module with much more SLOCs 1240: 464: if pos.line >= coverArrayInit.length do return; -: 465: 1240: 466: coverArrayInit.ptr[pos.line] = zero32; 1240: 467: var auto t = getTypeIr(TypeU32.instance()); 1240: 468: var auto l = constBuilder.int(t, pos.line, false); 1240: 469: var auto p = instrBuilder.gep(getTypeIr(unitNode.coverData.type), coverArrayIr, [zero32, l]); 1240: 470: var auto n = instrBuilder.load(t, p); 1240: 471: var auto m = instrBuilder.add(n, one32); -: 472: 1240: 473: instrBuilder.store(m, p); 1240: 474: } -: 475: -: 476: /// Makes the allocas for **all** the local vars (on function entry). -: 477: /// This is to prevent many stacksave/stackrestore, e.g that would be caused by loops -: 478: function createLocalVarsAllocas(FunctionDeclaration* node) -: 479: { 3948: 480: foreach const auto vd in node.allocas do -: 481: { 9009: 482: visitConcreteType(vd.type); 9009: 483: if isImmediate in vd.flags && vd.context != localForeach do 1186: 484: continue; 7823: 485: var auto ir = instrBuilder.alloca(getTypeIr(vd.type)); 7823: 486: vd.ir = ir:u8*; -: 487: 7823: 488: var auto ta = asTypeAggregate(vd.type); 7823: 489: ta = ta && ta.declaration.defaultDtor ? ta else null; -: 490: } 3948: 491: } -: 492: -: 493: /// Returns: set | (1 << member) -: 494: function enumsetInclude(LLVMValueRef set; LLVMValueRef member): LLVMValueRef -: 495: { 105: 496: var auto mp2 = instrBuilder.shl(constBuilder.int(LLVMTypeOf(member), 1, false), member); 105: 497: return instrBuilder.or(set, mp2); -: 498: } -: 499: -: 500: /// Returns: set & ~(1 << member) -: 501: function enumsetExclude(LLVMValueRef set; LLVMValueRef member): LLVMValueRef -: 502: { 56: 503: var auto mp2 = instrBuilder.shl(constBuilder.int(LLVMTypeOf(member), 1, false), member); 56: 504: var auto neg = instrBuilder.xor(mp2, constBuilder.int(LLVMTypeOf(set), u64.max, false)); 56: 505: return instrBuilder.and(set, neg); -: 506: } -: 507: -: 508: /// include or exclude, used by IndexExp on var of type TypeEnumSet -: 509: function enumSetIncludeOrExclude(LLVMValueRef setPtr; LLVMValueRef setVal; LLVMValueRef member; LLVMValueRef action) -: 510: { 31: 511: var auto exclBr = instrBuilder.appendBasicBlock(currentFunction); 31: 512: var auto inclBr = instrBuilder.appendBasicBlock(currentFunction); 31: 513: var auto doneBr = instrBuilder.appendBasicBlock(currentFunction); -: 514: 31: 515: var auto z = constBuilder.int(LLVMTypeOf(action), 0, false); 31: 516: var auto cmp = instrBuilder.icmp(LLVMIntPredicate.EQ, action, z); 31: 517: instrBuilder.condBr(cmp, exclBr, inclBr); -: 518: 31: 519: startBlock(exclBr); 31: 520: instrBuilder.store(enumsetExclude(setVal, member), setPtr); 31: 521: exp = constBuilder.int(getTypeIr(TypeBool.instance()), 0, false); 31: 522: instrBuilder.br(doneBr); -: 523: 31: 524: startBlock(inclBr); 31: 525: instrBuilder.store(enumsetInclude(setVal, member), setPtr); 31: 526: exp = constBuilder.int(getTypeIr(TypeBool.instance()), 1, false); 31: 527: instrBuilder.br(doneBr); -: 528: 31: 529: startBlock(doneBr); 31: 530: } -: 531: -: 532: /// Returns: if not `setInSet` then `(set & (1 << member)) != 0` else ` member & set == member` -: 533: function enumsetIsIncluded(LLVMValueRef set; LLVMValueRef member; bool setInSet = false): LLVMValueRef -: 534: { 229: 535: if setInSet do -: 536: { 8: 537: exp = instrBuilder.and(member, set); 8: 538: exp = instrBuilder.icmp(LLVMIntPredicate.EQ, exp, member); -: 539: } -: 540: else do -: 541: { 221: 542: var auto mp2 = instrBuilder.shl(constBuilder.int(LLVMTypeOf(member), 1, false), member); 221: 543: exp = instrBuilder.and(set, mp2); 221: 544: exp = instrBuilder.shr(exp, member); 221: 545: exp = instrBuilder.truncOrBitCast(exp, getTypeIr(TypeBool.instance())); -: 546: } 229: 547: return exp; -: 548: } -: 549: -: 550: @destructor function destroy() -: 551: { 282: 552: vtableOwners.destroy(); 282: 553: functions.destroy(); 282: 554: functions2.destroy(); 282: 555: copiedToLocal.destroy(); 282: 556: coverArrayInit.decref; 282: 557: visited.destroy(); 282: 558: staticCtors.decref; 282: 559: staticDtors.decref; 282: 560: } -: 561: -: 562: function finalizeDI() -: 563: { 282: 564: if !diGenerate do 235: 565: return; 47: 566: diBuilder.finalize(); 47: 567: delete diBuilder; 47: 568: } -: 569: -: 570: function generateAsmBody(FunctionDeclaration* node) -: 571: { 4: 572: const s8[] name = `"` ~ node.linkageName ~ `"`; 4: 573: const s8[] header = ".text\n.globl " ~ name ~ "\n.p2align 4,,15\n.type " ~ -: 574: name ~ ", @function\n" ~ name ~ ":\n"; 4: 575: LLVMAppendModuleInlineAsm(unitIr, header.ptr, header.length); 4: 576: var auto se = asStringExp(node.asmBody); 4: 577: LLVMAppendModuleInlineAsm(unitIr, se.value.text().ptr, se.value.text().length); 4: 578: const s8[] tail = ".size " ~ name ~ ", .-" ~ name; 4: 579: LLVMAppendModuleInlineAsm(unitIr, tail.ptr, tail.length); 4: 580: } -: 581: -: 582: function getAttrInlineAlways(): LLVMAttributeRef -: 583: { 41: 584: return attrInlineAlways ?= getLLVMAttribute(ctxt, "alwaysinline"); -: 585: } -: 586: -: 587: function getAttrInlineMaybe(): LLVMAttributeRef -: 588: { 304: 589: return attrInlineMaybe ?= getLLVMAttribute(ctxt, "inlinehint"); -: 590: } -: 591: -: 592: function getAttrInlineNo(): LLVMAttributeRef -: 593: { 23788: 594: return attrInlineNo ?= getLLVMAttribute(ctxt, "noinline"); -: 595: } -: 596: -: 597: function getAttrOptNone(): LLVMAttributeRef -: 598: { 1: 599: return attrOptNone ?= getLLVMAttribute(ctxt, "optnone"); -: 600: } -: 601: -: 602: function getAttrNoReturn(): LLVMAttributeRef -: 603: { 5: 604: return attrNoReturn ?= getLLVMAttribute(ctxt, "noreturn"); -: 605: } -: 606: -: 607: function escapeFront(): LLVMValueRef -: 608: { 260: 609: var auto t = getPointerTypeIr(TypeU8.instance()); 260: 610: if !escapeFrontVar do -: 611: { 11: 612: escapeFrontVar = LLVMAddGlobal(unitIr, t, (unitNode.linkageName ~ "__sx_escape_stack\0").ptr); 11: 613: LLVMSetInitializer(escapeFrontVar, constBuilder.zeroInit(t)); 11: 614: if !session.noTlsEscapes do 11: 615: LLVMSetThreadLocalMode(escapeFrontVar, GeneralDynamicTLSModel); -: 616: } 260: 617: return instrBuilder.load(t, escapeFrontVar); -: 618: } -: 619: -: 620: function escapePop() -: 621: { 149: 622: const auto t = getPointerTypeIr(TypeU8.instance()); 149: 623: var auto v = instrBuilder.gep(t, escapeFront(), [zero32]); 149: 624: v = instrBuilder.load(t, v); 149: 625: instrBuilder.store(v, escapeFrontVar); 149: 626: } -: 627: -: 628: function escapePrepare(FunctionDeclaration* node) -: 629: { 3948: 630: inNestedFunc = false; 3948: 631: currentEscapes = null; 3948: 632: var auto escapes = node.escapes[]; 3948: 633: if isNested in node.flags do 94: 634: inNestedFunc = true; 3948: 635: if !escapes do 3928: 636: return; -: 637: -: 638: // type for the struct containing pointer to the previous escapes struct + those to the escaped allocas 20: 639: var auto mt = (new LLVMTypeRef[+])(escapes.length + 1); 20: 640: mt[0] = getPointerTypeIr(TypeU8.instance()); 20: 641: foreach (const auto i; var auto e) in escapes do -: 642: { 39: 643: visitConcreteType(e.type); 39: 644: mt.ptr[i + 1] = getPointerTypeIr(e.type); -: 645: } 20: 646: var auto st = LLVMStructTypeInContext(ctxt, mt.ptr, mt.length:u32, false); -: 647: // store the pointer to the escaped allocas 20: 648: currentEscapes = instrBuilder.alloca(st); 20: 649: instrBuilder.store(escapeFront(), instrBuilder.structGep(st, currentEscapes, 0)); 20: 650: foreach (const auto i; var auto e) in escapes do -: 651: { 39: 652: var auto ep = instrBuilder.structGep(st, currentEscapes, i + 1); 39: 653: var auto ev = nodeIRtoValueRef(e); 39: 654: instrBuilder.store(ev, ep); -: 655: } 20: 656: instrBuilder.store(currentEscapes, escapeFrontVar); 20: 657: } -: 658: -: 659: /// called on late stage, once all classes are visited to write the actuall addresses contained in the vtable -: 660: function fixupVtable(AggregateDeclaration* node) -: 661: { 20266: 662: assert(node.vtableVar.ir); 20266: 663: foreach var auto t in node.inheritanceList do -: 664: { 31592: 665: if var auto tc = asTypeClass(t) do 15796: 666: fixupVtable(tc.declaration); -: 667: } 20266: 668: var auto vtableIr = nodeIRtoValueRef(node.vtableVar); 20266: 669: if isImported(node) do -: 670: { 19410: 671: LLVMSetLinkage(vtableIr, LLVMLinkage.ExternalLinkage); 19410: 672: return; -: 673: } -: 674: 856: 675: var auto vtable = (new LLVMValueRef[+])(node.vtable.length + 1); 856: 676: var auto u8PtrIr = getPointerTypeIr(TypeU8.instance()); 856: 677: if node.inheritanceList.length do -: 678: { 767: 679: var auto tc = asTypeClass(node.inheritanceList[0]); 767: 680: vtable.ptr[0] = nodeIRtoValueRef(tc.declaration.vtableVar); -: 681: } 89: 682: else do vtable.ptr[0] = nullPtr; -: 683: 16492: 684: eachCounted:[function[I, T](I i; T fd) => vtable.ptr[i + 1] = constBuilder.bitCast(nodeIRtoValueRef(fd), u8PtrIr)](node.vtable); -: 685: 856: 686: var auto v = constBuilder.array(u8PtrIr, vtable); 856: 687: LLVMSetInitializer(vtableIr, v); 856: 688: } -: 689: -: 690: // decref a local rc array -: 691: function freeManagedRca(AstNode* diLoc; LLVMValueRef v; TypeRcArray* tra; bool isLvalue) -: 692: { 1665: 693: var auto thisArg = isLvalue ? instrBuilder.load(rcaType, v) else v; 1665: 694: var auto decrBr = instrBuilder.appendBasicBlock(currentFunction); 1665: 695: var auto doneBr = instrBuilder.appendBasicBlock(currentFunction); 1665: 696: var auto iptr = instrBuilder.ptrToInt(thisArg, getTypeIr(TypeUSize())); 1665: 697: var auto cmp = instrBuilder.icmp(LLVMIntPredicate.NE, iptr, zerosize); 1665: 698: instrBuilder.condBr(cmp, decrBr, doneBr); 1665: 699: startBlock(decrBr); -: 700: var LLVMValueRef e; 1665: 701: if tra.nestedRcArrayDims do -: 702: { 7: 703: var auto d = constBuilder.int(getTypeIr(TypeU8.instance()), tra.nestedRcArrayDims, false); 7: 704: e = instrBuilder.call(rtl_rcaDecRefCountNest().tupleof, [thisArg, d]); -: 705: } 1658: 706: else do e = instrBuilder.call(rtl_rcaDecRefCount().tupleof, getRcaDecrementArgs(tra, thisArg)); 1665: 707: if isLvalue do 1665: 708: instrBuilder.store(e, v); 1665: 709: instructionDi(diLoc, e); 1665: 710: instrBuilder.br(doneBr); 1665: 711: startBlock(doneBr); 1665: 712: } -: 713: -: 714: /// decref rca contained in local tuples -: 715: function freeManagedLocalsInTuple(AstNode* diLoc; LLVMValueRef v; TypeTuple* tt) -: 716: { 14: 717: const auto ta = getTypeIr(tt); 14: 718: foreach (const auto i; const auto t) in tt.types do -: 719: { 28: 720: var auto e = instrBuilder.structGep(ta, v, i); 56: 721: if var auto tra = asTypeRcArray(t) do 8: 722: freeManagedRca(diLoc, e, tra, true); 40: 723: else do if var auto tt2 = asTypeTuple(t) do 2: 724: freeManagedLocalsInTuple(diLoc, e, tt2); 36: 725: else do if var auto tsa = asTypeStaticArray(t) do 4: 726: freeManagedLocalsInStaticArray(diLoc, e, tsa); -: 727: } 14: 728: } -: 729: -: 730: /// decref rca contained in local static arrays -: 731: function freeManagedLocalsInStaticArray(AstNode* diLoc; LLVMValueRef v; TypeStaticArray* tsa) -: 732: { 18: 733: var auto bt = getTypeIr(tsa); 18: 734: var auto tra = asTypeRcArray(tsa.modified); 18: 735: var auto tt = asTypeTuple(tsa.modified); 18: 736: var auto ts1 = asTypeStaticArray(tsa.modified); 18: 737: var auto ti = getTypeIr(TypeU32.instance()); 18: 738: if tra || tt || ts1 do 18: 739: foreach const auto i in 0 .. tsa.length() do -: 740: { 18: 741: const auto ie = constBuilder.int(ti, i, false); 18: 742: const auto ve = instrBuilder.gep(bt, v, [zero32, ie]); 18: 743: if tra do 12: 744: freeManagedRca(diLoc, ve, tra, true); 6: 745: else do if tt do 4: 746: freeManagedLocalsInTuple(diLoc, ve, tt); 2: 747: else do if ts1 do 2: 748: freeManagedLocalsInStaticArray(diLoc, ve, ts1); -: 749: } 18: 750: } -: 751: -: 752: /// generate call to decref and call dtors of locals that go out of scope -: 753: function freeManagedLocals(AstNode* diLoc; VariableDeclaration*[] managedLocals) -: 754: { 11365: 755: foreach const auto vd in managedLocals do -: 756: { 3674: 757: if var auto tt = asTypeTuple(vd.type) do 8: 758: freeManagedLocalsInTuple(diLoc, nodeIRtoValueRef(vd), tt); 3658: 759: else do if var auto tsa = asTypeStaticArray(vd.type) do 12: 760: freeManagedLocalsInStaticArray(diLoc, nodeIRtoValueRef(vd), tsa); -: 761: // `free(slice.ptr); slice.ptr = null;` 3634: 762: else do if var auto tsl = vd.type.asTypeSlice() do -: 763: { 224: 764: if var auto v = nodeIRtoValueRef(vd) do -: 765: { 112: 766: const auto tel = getPointerTypeIr(tsl.modified); 112: 767: var auto ptrW = instrBuilder.structGep(getTypeIr(tsl), v, TSliceLayout.ptrIdx); 112: 768: var auto ptrR = instrBuilder.load(tel, ptrW); -: 769: //runTimePrintf("try to free managed array `" ~ vd.name.text() ~ "` at `%p`\n\0", [ptrR]); 112: 770: instrBuilder.free(ptrR); 112: 771: instrBuilder.store(nullPtr, ptrW); -: 772: //printf("added code to free %s.ptr memory\n", vd.name.text().ptr); -: 773: //runTimePrintf("done free managed array `" ~ vd.name.text() ~ "` at `%p`\n\0", [ptrR]); -: 774: } -: 775: } -: 776: // `if (rc_array) rc_array.decref;` 3410: 777: else do if var auto tra = vd.type.asTypeRcArray() do -: 778: { 3290: 779: if var auto v = nodeIRtoValueRef(vd) do 1645: 780: freeManagedRca(diLoc, v, tra, true); -: 781: } -: 782: // `destroy(stackAllocdStructOrClass);` 60: 783: else do aggregateDtor(vd.type, nodeIRtoValueRef(vd), diLoc); -: 784: } 11365: 785: } -: 786: -: 787: /// -: 788: function functionDeclarationDI(FunctionDeclaration* node) -: 789: { 4439: 790: if !diGenerate || !node.body do 2318: 791: return; -: 792: 2121: 793: var LLVMMetadataRef[+] paramsTypeRef = (new LLVMMetadataRef[+])(node.parameters.length); 2121: 794: foreach (const auto i; var auto p) in node.parameters do -: 795: { 3411: 796: var auto t = p.type.resolved(); 3411: 797: visitConcreteType(t); 3411: 798: paramsTypeRef.ptr[i] = getTypeDi(t); -: 799: } -: 800: 2121: 801: var auto f = nodeIRtoValueRef(node); 2121: 802: var auto flags = LLVMDIFlags.Prototyped; 2121: 803: var auto ft = diBuilder.createSubroutineType(paramsTypeRef, LLVMDIFlags.Zero); 2121: 804: var auto di = diBuilder.createFunction(node.linkageName[], node.startPos.line, ft, true, true, false, flags, f); 2121: 805: diScope = di; 2121: 806: } -: 807: -: 808: /// -: 809: function generateAbstractBody(FunctionDeclaration* node) -: 810: { 5: 811: var auto oldFunc = currentFunction; 5: 812: currentFunction = nodeIRtoValueRef(node); 5: 813: var auto entry = instrBuilder.appendBasicBlock(currentFunction); -: 814: 5: 815: LLVMAddAttributeAtIndex(currentFunction, LLVMAttributeIndex.Function, getAttrNoReturn()); 5: 816: startBlock(entry); -: 817: 5: 818: abstractSpecifier ?= instrBuilder.globalStringPtr("runtime error, call to `@abstract` function `%s`\n"); 5: 819: var auto name = instrBuilder.globalStringPtr(node.symbol.fqn(false).tokenChainText() ~ "\0"[]); 5: 820: generateCheckFail([abstractSpecifier, name]); -: 821: 5: 822: currentFunction = oldFunc; 5: 823: } -: 824: -: 825: /// subroutine used by all the `--check` and when on failure: printf message and crash the application -: 826: function generateCheckFail(LLVMValueRef[] printfArgs) -: 827: { 12707: 828: instrBuilder.call(libc_printf().tupleof, printfArgs); 12707: 829: instrBuilder.call(libc_fflush().tupleof, [zerosize]); 12707: 830: instrBuilder.call(llvm_trap().tupleof, []); 12707: 831: instrBuilder.unreachable(); 12707: 832: } -: 833: -: 834: /// very LLVM-speific stuff for the static ctors -: 835: function generateStaticCtorsSpecialVariable() -: 836: { 282: 837: if !staticCtors.length do 274: 838: return; -: 839: 8: 840: var auto entriesVal = (new LLVMValueRef[+])(staticCtors.length); 8: 841: foreach (const auto i; var auto fd) in staticCtors do -: 842: { 14: 843: var auto ctorIndex = constBuilder.int(getTypeIr(TypeU32.instance()), i, false); 14: 844: var auto ctorPtr = nodeIRtoValueRef(fd); 14: 845: entriesVal.ptr[i] = constBuilder.namedStruct(staticCtorEntryType(), [ctorIndex, ctorPtr, nullPtr]); -: 846: } 8: 847: var auto entriesInit = constBuilder.array(staticCtorEntryType(), entriesVal); 8: 848: var auto ctorEntries = LLVMAddGlobal(unitIr, LLVMTypeOf(entriesInit), "llvm.global_ctors"); 8: 849: LLVMSetInitializer(ctorEntries, entriesInit); 8: 850: LLVMSetLinkage(ctorEntries, LLVMLinkage.AppendingLinkage); 8: 851: } -: 852: -: 853: /// very LLVM-speific stuff for the static dtors -: 854: function generateStaticDtorsSpecialVariable() -: 855: { 282: 856: if !staticDtors.length && !coverageFinalizer do 261: 857: return; -: 858: 21: 859: var auto entriesVal = (new LLVMValueRef[+])(staticDtors.length + doCover); 21: 860: if coverageFinalizer do -: 861: { 10: 862: var auto dtorIndex = constBuilder.int(getTypeIr(TypeU32.instance()), 0, false); 10: 863: entriesVal.ptr[0] = constBuilder.namedStruct(staticCtorEntryType(), [dtorIndex, coverageFinalizer, nullPtr]); -: 864: } 21: 865: foreach (const auto i; var auto fd) in staticDtors.reverse do -: 866: { 60: 867: var auto dtorIndex = constBuilder.int(getTypeIr(TypeU32.instance()), i + doCover, false); 60: 868: var auto dtorPtr = nodeIRtoValueRef(fd); 60: 869: entriesVal.ptr[i + doCover] = constBuilder.namedStruct(staticCtorEntryType(), [dtorIndex, dtorPtr, nullPtr]); -: 870: } 21: 871: var auto entriesInit = constBuilder.array(staticCtorEntryType(), entriesVal); 21: 872: var auto dtorEntries = LLVMAddGlobal(unitIr, LLVMTypeOf(entriesInit), "llvm.global_dtors"); 21: 873: LLVMSetInitializer(dtorEntries, entriesInit); 21: 874: LLVMSetLinkage(dtorEntries, LLVMLinkage.AppendingLinkage); 21: 875: } -: 876: -: 877: /// Returns: info used to generate decls ir only once and in the right LLVM module -: 878: function getDeclModuleInfo(Declaration* node): DeclModuleInfo -: 879: { 290613: 880: var auto isVisited = node.progress == irgened; 290613: 881: var auto result = DeclModuleInfo.create(isImported(node), isVisited); 376732: 882: if !isVisited do visited.append(node); 290613: 883: node.progress = irgened; 290613: 884: return result; -: 885: } -: 886: -: 887: /// Returns: the init value, either custom or the default, for a variable declaration. -: 888: function getInitializer(VariableDeclaration* node): LLVMValueRef -: 889: { 47407: 890: return node.initializer ? nodeIRtoValueRef(node.initializer) else 47055: 891: node.getAtNoinit() ? constBuilder.undef(getTypeIr(node.type)) else 46991: 892: getTypeInitIr(node.type); -: 893: } -: 894: -: 895: /// Returns: position line and column as const i32 array -: 896: function getLineCol(var Position pos): LLVMValueRef[2] -: 897: { 12603: 898: var auto type = getTypeIr(TypeU32.instance()); 12603: 899: return [constBuilder.int(type, pos.line, false), constBuilder.int(type, pos.column, false)]; -: 900: } -: 901: -: 902: /// Returns: array of debug info for the members of an aggregate -: 903: function getMemberDi(Symbol* s): LLVMMetadataRef[+] -: 904: { -: 905: var LLVMMetadataRef[+] diMembers; 4571: 906: foreach var auto c in s.children do -: 907: { 30452: 908: var auto vd = symToVarDecl(c); 51580: 909: if !vd do continue; -: 910: 9324: 911: var auto mtype = vd.type.resolved(); 9324: 912: var auto mname = vd.name.text(); 9324: 913: if !vd.isStatic() do -: 914: { 8727: 915: diMembers ~= diBuilder.createMemberType(diScope, mname, vd.startPos.line, -: 916: mtype.size, mtype.align, vd.offset, LLVMDIFlags.Zero, getTypeDi(mtype)); -: 917: } -: 918: else do -: 919: { 597: 920: diBuilder.createStaticMemberType(diScope, mname, vd.startPos.line, -: 921: mtype.align, LLVMDIFlags.Zero, getTypeDi(mtype), null); -: 922: } -: 923: } 4571: 924: return diMembers; -: 925: } -: 926: -: 927: function getRcaDecrementArgs(const TypeRcArray* t; const LLVMValueRef thisArg): LLVMValueRef[3] -: 928: { 4644: 929: if var auto ta = asTypeAggregate(t.modified) do 30: 930: if var auto fd = ta.declaration.defaultDtor do -: 931: { 9: 932: if !fd.ir do visitFunctionDeclaration(fd); 7: 933: const auto bitSz = ta.size + ta.align; 7: 934: return [thisArg, nodeIRtoValueRef(fd), constBuilder.int(getTypeIr(TypeU32.instance()), bitSz, false)]; -: 935: } 2315: 936: return [thisArg, nullPtr, zero32]; -: 937: } -: 938: -: 939: function initializeDI() -: 940: { 283: 941: if !diGenerate do 236: 942: return; -: 943: 47: 944: var auto t = LLVMInt32TypeInContext(ctxt); 47: 945: var auto dwarfVerNum = constBuilder.int(t, 2, false); 47: 946: var auto dbgVerNum = constBuilder.int(t, 3, false); 47: 947: LLVMAddModuleFlag(unitIr, LLVMModuleFlagBehavior.Warning, "Dwarf Version", 13, LLVMValueAsMetadata(dwarfVerNum)); 47: 948: LLVMAddModuleFlag(unitIr, LLVMModuleFlagBehavior.Warning, "Debug Info Version", 18, LLVMValueAsMetadata(dbgVerNum)); -: 949: 47: 950: var auto fn = baseName(unitNode.scope.filename); 47: 951: var auto dn = absolutePath(dirName(unitNode.scope.filename)); 47: 952: var auto vn = versionToken().text(); 47: 953: diBuilder = (new DIBuilder).create(ctxt, unitIr); 47: 954: diScope = diBuilder.createFile(fn, dn); 47: 955: diUnitRef = diBuilder.createCompileUnit(vn, session.optLevel != 0); 47: 956: } -: 957: -: 958: /// Prepare the IR for all the basic types, their pointer types and common constants -: 959: /// This is because they are not automatically visited but often required, e.g by the libc_xxxx -: 960: function initialize() -: 961: { 283: 962: visitTypeBool(TypeBool.instance()); 283: 963: visitTypeVoid(TypeVoid.instance()); -: 964: 283: 965: visitTypeU8(TypeU8.instance()); 283: 966: visitTypeU16(TypeU16.instance()); 283: 967: visitTypeU32(TypeU32.instance()); 283: 968: visitTypeU64(TypeU64.instance()); -: 969: 283: 970: visitTypeS8(TypeS8.instance()); 283: 971: visitTypeS16(TypeS16.instance()); 283: 972: visitTypeS32(TypeS32.instance()); 283: 973: visitTypeS64(TypeS64.instance()); -: 974: 283: 975: visitTypeF32(TypeF32.instance()); 283: 976: visitTypeF64(TypeF64.instance()); -: 977: 283: 978: zero32 = constBuilder.int(getTypeIr(TypeU32.instance()), 0, false); 283: 979: zero8 = constBuilder.int(getTypeIr(TypeU8.instance()), 0, false); 283: 980: one32 = constBuilder.int(getTypeIr(TypeU32.instance()), 1, false); 283: 981: minusOne32 = constBuilder.int(getTypeIr(TypeU32.instance()), u64.max, true); 283: 982: zerosize = constBuilder.int(getTypeIr(TypeUSize()), 0, false); 283: 983: onesize = constBuilder.int(getTypeIr(TypeUSize()), 1, false); 283: 984: nullPtr = constBuilder.$null(getPointerTypeIr(TypeUSize())); -: 985: 283: 986: var auto tl = getTypeIr(TypeUSize()); 283: 987: var auto ts = LLVMStructTypeInContext(ctxt, [tl, tl].ptr, 2, false); 283: 988: rcaTypePointee = ts; 283: 989: rcaType = LLVMPointerType(ts, 0); 283: 990: } -: 991: -: 992: /// generate debug info for an instruction -: 993: function instructionDi(AstNode* node; LLVMValueRef e) -: 994: { 67460: 995: if !diGenerate do 23619: 996: return; -: 997: // e.g `1 + 1`, becomes a LLVMConstAdd (or already a value ?) -: 998: // but at least something with an invalid LLVMOpcode (0). -: 999: // leading to random LLVM crashes and when using LLVMPrintModuleToFile() 43841:1000: if LLVMGetInstructionOpcode(e) != 0 do -:1001: { 43068:1002: var auto loc = diBuilder.createDebugLocation(node.startPos.line, node.startPos.column, diScope, null); 43068:1003: LLVMInstructionSetDebugLoc(e, loc); -:1004: } 43841:1005: } -:1006: -:1007: /// Returns: if the symbol is imported, allowing to skip function bodies -:1008: function isImported(const Declaration* node): bool -:1009: { 353938:1010: return node.scope.filename.ptr != unitNode.filename.ptr; -:1011: } -:1012: -:1013: /// Returns: libc fflush() -:1014: function libc_fflush(): var FuncTyAndPtr -:1015: { 25418:1016: if !fflushRef.func do -:1017: { 195:1018: fflushRef.type = LLVMFunctionType(getTypeIr(TypeS32.instance()), [getTypeIr(TypeUSize())].ptr, 1, false); 195:1019: fflushRef.func = LLVMAddFunction(unitIr, "fflush", fflushRef.type); -:1020: } 25418:1021: return fflushRef; -:1022: } -:1023: -:1024: /// Returns: libc memcmp() -:1025: function libc_memcmp(): var FuncTyAndPtr -:1026: { 237:1027: if !memcmpRef.func do -:1028: { 28:1029: var auto pt = getPointerTypeIr(TypeU8.instance()); 28:1030: memcmpRef.type = LLVMFunctionType(getTypeIr(TypeS32.instance()), [pt, pt, getTypeIr(TypeUSize())].ptr, 3, false); 28:1031: memcmpRef.func = LLVMAddFunction(unitIr, "memcmp", memcmpRef.type); -:1032: } 237:1033: return memcmpRef; -:1034: } -:1035: -:1036: /// Returns: libc printf() -:1037: function libc_printf(): var FuncTyAndPtr -:1038: { 25493:1039: if !printfRef.func do -:1040: { 206:1041: printfRef.type = LLVMFunctionType(getTypeIr(TypeS32.instance()), [getPointerTypeIr(TypeU8.instance())].ptr, 1, true); 206:1042: printfRef.func = LLVMAddFunction(unitIr, "printf", printfRef.type); -:1043: } 25493:1044: return printfRef; -:1045: } -:1046: -:1047: /// Returns: (libc realloc(), its type) -:1048: function libc_realloc(): var FuncTyAndPtr -:1049: { 222:1050: if !reallocRef.func do -:1051: { 64:1052: var auto pt = getPointerTypeIr(TypeU8.instance()); 64:1053: reallocRef.type = LLVMFunctionType(pt, [pt, getTypeIr(TypeUSize())].ptr, 2, false); 64:1054: reallocRef.func = LLVMAddFunction(unitIr, "realloc", reallocRef.type); -:1055: } 222:1056: return reallocRef; -:1057: } -:1058: -:1059: /// Returns dbg.declare() instrinsic (`void @llvm.dbg.declare(metadata, metadata, metadata)`) -:1060: function llvm_dbg_declare(): var FuncTyAndPtr -:1061: { 14418:1062: if !dbgDeclareRef.func do -:1063: { 45:1064: const u32 id = LLVMLookupIntrinsicID("llvm.dbg.declare", 16); 45:1065: dbgDeclareRef.type = LLVMIntrinsicGetType(ctxt, id, null, 0); 45:1066: dbgDeclareRef.func = LLVMGetIntrinsicDeclaration(unitIr, id, null, 0); -:1067: } 14418:1068: return dbgDeclareRef; -:1069: } -:1070: -:1071: /// Returns: trap() intrinsic (`function llvm.trap()`) -:1072: function llvm_trap(): var FuncTyAndPtr -:1073: { 25892:1074: if !trapRef.func do -:1075: { 205:1076: const u32 id = LLVMLookupIntrinsicID("llvm.trap", 9); 205:1077: trapRef.type = LLVMIntrinsicGetType(ctxt, id, null , 0); 205:1078: trapRef.func = LLVMGetIntrinsicDeclaration(unitIr, id, null, 0); -:1079: } 25892:1080: return trapRef; -:1081: } -:1082: -:1083: /// Returns: The visitor member `exp`, after a load if the input expression is a lvalue and directly otherwise -:1084: function loadExpIfLvalue(Expression* node): LLVMValueRef -:1085: { 122264:1086: return node.isLvalue() ? exp = instrBuilder.load(getTypeIr(node.type), exp) else exp; -:1087: } -:1088: -:1089: /// Handle the conflicts between user `@foreign` functions and auto-generated libc_xxx ones -:1090: function matchImplicitLibcDecl(FunctionDeclaration* node): bool -:1091: { 1722:1092: const auto nodeName = node.name.iptr(); 1722:1093: static const auto pairs = [(&libcPrintfToken.get, &libc_printf), -:1094: (&libcFFlushToken.get, &libc_fflush), -:1095: (&libcReallocToken.get, &libc_realloc), -:1096: (&libcMemcmpToken.get, &libc_memcmp)]; 1722:1097: foreach const auto p in pairs do -:1098: { -:1099: alias getLibcFuncName => p[0]().iptr(); -:1100: alias getLibcFuncRef => p[1](); 6597:1101: if nodeName == getLibcFuncName do -:1102: { 130:1103: const auto r = getLibcFuncRef; 130:1104: node.ir = r.func:u8*; 130:1105: setTypeIr(node.asTypeDeclared, r.type, null); 130:1106: node.progress = irgened; 130:1107: visited.append(node); 130:1108: return true; -:1109: } -:1110: } 1592:1111: return false; -:1112: } -:1113: -:1114: /// OptAccessExp is grammatically an PreExp but is not really one... -:1115: /// This does the Postfix part of the expression, i.e select the value from a phi -:1116: function optAccessFinalize(OptAccessExpression* node) -:1117: { 158:1118: var auto oe = node.ir:OptExpIr*; 158:1119: var auto lv = oe.skippedValue; 158:1120: var auto lb = oe.skippedValueBr; 158:1121: var auto rv = exp; 158:1122: var auto rb = currentBlock; 158:1123: instrBuilder.br(oe.phiBr); -:1124: 158:1125: startBlock(oe.phiBr); 158:1126: var auto t = node.valueVar ? getPointerTypeIr(node.valueType) else getTypeIr(node.valueType); 158:1127: if oe.isPhiNeeded do -:1128: { 71:1129: exp = instrBuilder.phi(t); 71:1130: instrBuilder.addIncoming(exp, [lv, rv], [lb, rb]); -:1131: } 87:1132: else do exp = null; 158:1133: } -:1134: -:1135: /// If `node` is for a `TypeRcArray`, increment the reference count of the array given by `expIr` -:1136: function rcaIncrement(Expression* node; LLVMValueRef expIr) -:1137: { -:1138: function deepRcaIncrement(Type* type; AstNode* dbgLoc; LLVMValueRef e) -:1139: { 12042:1140: if LLVMGetTypeKind(LLVMTypeOf(e)) != LLVMTypeKind.PointerTypeKind do 1504:1141: return; 21076:1142: if var auto tra = asTypeRcArray(type) do -:1143: { 899:1144: var auto a = instrBuilder.load(rcaType, e); 899:1145: var auto d = instrBuilder.call(rtl_rcaIncRefCount().tupleof, [a]); 899:1146: instructionDi(dbgLoc, d); -:1147: } 19278:1148: else do if var auto tt = asTypeTuple(type) do -:1149: { 51:1150: visitTypeTuple(tt); 51:1151: const auto ta = getTypeIr(tt); 51:1152: foreach (const auto i; const auto t) in tt.types do -:1153: { 106:1154: const auto tra = asTypeRcArray(t); 106:1155: const auto ttp = asTypeTuple(t); 106:1156: const auto tsa = asTypeStaticArray(t); 106:1157: if tra || ttp || tsa do 19:1158: deepRcaIncrement(t, dbgLoc, instrBuilder.structGep(ta, e, i)); -:1159: } -:1160: } 19176:1161: else do if var auto tsa = asTypeStaticArray(type) do -:1162: { 197:1163: const auto tra = asTypeRcArray(tsa.modified); 197:1164: const auto ttp = asTypeTuple(tsa.modified); 197:1165: const auto ts1 = asTypeStaticArray(tsa.modified); 197:1166: const auto ti = getTypeIr(TypeU32.instance()); 197:1167: const auto bt = getTypeIr(tsa); 223:1168: if tra || ttp || ts1 do foreach const auto i in 0 .. tsa.length() do -:1169: { 29:1170: const auto ci = constBuilder.$int(ti, i, false); 29:1171: deepRcaIncrement(tsa.modified, dbgLoc, instrBuilder.gep(bt, e, [zero32, ci])); -:1172: } -:1173: } 10538:1174: } 11994:1175: deepRcaIncrement(node.type, node, expIr); 11994:1176: } -:1177: -:1178: /// If `node` is for a `TypeRcArray`, decrement the reference count of the array given by `expIr` -:1179: /// but without freeing the memory. This is so that `rca1 = getRca2()` works as `rca1 = rca2`. -:1180: function rcaBeforeReturn(Expression* node; LLVMValueRef expIr) -:1181: { -:1182: function deepRcaBeforeReturn(Type* type; AstNode* dbgLoc; LLVMValueRef e) -:1183: { 2924:1184: if LLVMGetTypeKind(LLVMTypeOf(e)) != LLVMTypeKind.PointerTypeKind do 1152:1185: return; 3544:1186: if var auto tra = asTypeRcArray(type) do -:1187: { 151:1188: var auto a = instrBuilder.load(rcaType, e); 151:1189: var auto d = instrBuilder.call(rtl_rcaBeforeReturn().tupleof, [a]); 151:1190: instructionDi(dbgLoc, d); -:1191: } 3242:1192: else do if var auto tt = asTypeTuple(type) do -:1193: { 4:1194: visitTypeTuple(tt); 4:1195: const auto ta = getTypeIr(tt); 4:1196: foreach (const auto i; const auto t) in tt.types do -:1197: { 8:1198: const auto tra = asTypeRcArray(t); 8:1199: const auto ttp = asTypeTuple(t); 8:1200: const auto tsa = asTypeStaticArray(t); 8:1201: if tra || ttp ||tsa do 2:1202: deepRcaBeforeReturn(t, dbgLoc, instrBuilder.structGep(ta, e, i)); -:1203: } -:1204: } 3234:1205: else do if var auto tsa = asTypeStaticArray(type) do -:1206: { 1:1207: const auto tra = asTypeRcArray(tsa.modified); 1:1208: const auto ttp = asTypeTuple(tsa.modified); 1:1209: const auto ts1 = asTypeStaticArray(tsa.modified); 1:1210: const auto ti = getTypeIr(TypeU32.instance()); 1:1211: const auto bt = getTypeIr(tsa); 2:1212: if tra || ttp || ts1 do foreach const auto i in 0 .. tsa.length() do -:1213: { 1:1214: const auto ci = constBuilder.$int(ti, i, false); 1:1215: deepRcaBeforeReturn(tsa.modified, dbgLoc, instrBuilder.gep(bt, e, [zero32, ci])); -:1216: } -:1217: } 1772:1218: } 2921:1219: deepRcaBeforeReturn(node.type, node, expIr); 2921:1220: } -:1221: -:1222: /// If `node` is for a `TypeRcArray`, decrement the reference count of the array given by `expIr` -:1223: function rcaDecrement(Expression* node; LLVMValueRef expIr) -:1224: { -:1225: function deepRcaDecrement(Type* type; AstNode* dbgLoc; LLVMValueRef e) -:1226: { 5425:1227: if LLVMGetTypeKind(LLVMTypeOf(e)) != LLVMTypeKind.PointerTypeKind do 0:1228: return; 10850:1229: if var auto tra = asTypeRcArray(type) do -:1230: { 590:1231: var auto a = instrBuilder.load(rcaType, e); 590:1232: var auto d = instrBuilder.call(rtl_rcaDecRefCount().tupleof, getRcaDecrementArgs(tra, a)); 590:1233: instructionDi(dbgLoc, d); -:1234: } 9670:1235: else do if var auto tt = asTypeTuple(type) do -:1236: { 13:1237: visitTypeTuple(tt); 13:1238: const auto ta = getTypeIr(tt); 13:1239: foreach (const auto i; const auto t) in tt.types do -:1240: { 26:1241: const auto tra = asTypeRcArray(t); 26:1242: const auto ttp = asTypeTuple(t); 26:1243: const auto tsa = asTypeStaticArray(t); 26:1244: if tra || ttp || tsa do 6:1245: deepRcaDecrement(t, dbgLoc, instrBuilder.structGep(ta, e, i)); -:1246: } -:1247: } 9644:1248: else do if var auto tsa = asTypeStaticArray(type) do -:1249: { 146:1250: const auto tra = asTypeRcArray(tsa.modified); 146:1251: const auto ttp = asTypeTuple(tsa.modified); 146:1252: const auto ts1 = asTypeStaticArray(tsa.modified); 146:1253: const auto ti = getTypeIr(TypeU32.instance()); 146:1254: const auto bt = getTypeIr(tsa); 155:1255: if tra || ttp || ts1 do foreach const auto i in 0 .. tsa.length() do -:1256: { 11:1257: const auto ci = constBuilder.$int(ti, i, false); 11:1258: deepRcaDecrement(tsa.modified, dbgLoc, instrBuilder.gep(bt, e, [zero32, ci])); -:1259: } -:1260: } 5425:1261: } 5408:1262: deepRcaDecrement(node.type, node, expIr); 5408:1263: } -:1264: -:1265: /** -:1266: * Reset the visitor member `exp`, visit the input and return `exp`. -:1267: * -:1268: * This is the idiomatic way to visit an Expression, -:1269: * e.g when the previous one is not required (call arg, if condition, etc.), -:1270: * because then the previous `exp` value cannot be re-used by error. */ -:1271: function resetAndVisitExp(Expression* node): LLVMValueRef -:1272: { 132524:1273: exp = null; 132524:1274: visitConcreteExpression(node); 132524:1275: return exp; -:1276: } -:1277: -:1278: /// Returns: rtl.dynCast (function dynCast(u8* src; u8* targetVtbl): u8*) -:1279: function rtl_dyncast(): var FuncTyAndPtr -:1280: { 92:1281: if !dynCastRef.func do -:1282: { 13:1283: var auto pt = getPointerTypeIr(TypeU8.instance()); 13:1284: dynCastRef.type = LLVMFunctionType(pt, [pt, pt].ptr, 2, false); 13:1285: dynCastRef.func = LLVMAddFunction(unitIr, "rtl.__sx_obj_dyncast", dynCastRef.type); -:1286: } 92:1287: return dynCastRef; -:1288: } -:1289: -:1290: function rtl_finalizeCovRef(): var FuncTyAndPtr -:1291: { 10:1292: if !finalizeCovRef.func do -:1293: { 10:1294: if isRtlRootUnit do -:1295: { 5:1296: var auto fd = unitNode.symbol.find(identifier("__sx_finalize_cov")).symToFuncDecl(); 5:1297: finalizeCovRef.type = getTypeIr(fd.asTypeDeclared); 5:1298: finalizeCovRef.func = nodeIRtoValueRef(fd); -:1299: } -:1300: else do -:1301: { 5:1302: var auto pta = getPointerTypeIr(TypeS32.instance()); 5:1303: var auto ptl = getTypeIr(TypeUSize()); 5:1304: var auto ptf = getPointerTypeIr(TypeS8.instance()); 5:1305: finalizeCovRef.type = LLVMFunctionType(getTypeIr(TypeVoid.instance()), [pta, ptl, ptf, ptf] .ptr, 4, false); 5:1306: finalizeCovRef.func = LLVMAddFunction(unitIr, "rtl.__sx_finalize_cov", finalizeCovRef.type); -:1307: } -:1308: } 10:1309: return finalizeCovRef; -:1310: } -:1311: -:1312: /// Returns: rtl.__sx_rc_append (`function __sx_rc_append(u8* array; u8* stuff; usize len; u32 elemBitSize): u8*`) -:1313: function rtl_rcaAppend(): var FuncTyAndPtr -:1314: { 1600:1315: if !rcaAppendRef.func do -:1316: { 78:1317: if isRtlRootUnit do -:1318: { 44:1319: const auto fd = unitNode.symbol.find(identifier("__sx_rc_append")).symToFuncDecl(); 44:1320: if !fd.ir do visitFunctionDeclaration(fd); 44:1321: rcaAppendRef.type = getTypeIr(fd.asTypeDeclared); 44:1322: rcaAppendRef.func = nodeIRtoValueRef(fd); -:1323: } -:1324: else do -:1325: { 34:1326: rcaAppendRef.type = LLVMFunctionType(rcaType, [rcaType, getPointerTypeIr(TypeU8.instance()), getTypeIr(TypeUSize()), getTypeIr(TypeU32.instance())].ptr, 4, false); 34:1327: rcaAppendRef.func = LLVMAddFunction(unitIr, "rtl.__sx_rc_append", rcaAppendRef.type); -:1328: } -:1329: } 1600:1330: return rcaAppendRef; -:1331: } -:1332: -:1333: /// Returns: rtl.__sx_rc_before_ret (`function __sx_rc_dec(u8* array): u8*`) -:1334: function rtl_rcaBeforeReturn(): var FuncTyAndPtr -:1335: { 302:1336: if !rcaBeforeReturnRef.func do -:1337: { 63:1338: if isRtlRootUnit do -:1339: { 44:1340: const auto fd = unitNode.symbol.find(identifier("__sx_rc_before_ret")).symToFuncDecl(); 44:1341: if !fd.ir do visitFunctionDeclaration(fd); 44:1342: rcaBeforeReturnRef.type = getTypeIr(fd.asTypeDeclared); 44:1343: rcaBeforeReturnRef.func = nodeIRtoValueRef(fd); -:1344: } -:1345: else do -:1346: { 19:1347: rcaBeforeReturnRef.type = LLVMFunctionType(getTypeIr(TypeVoid.instance()), &rcaType, 1, false); 19:1348: rcaBeforeReturnRef.func = LLVMAddFunction(unitIr, "rtl.__sx_rc_before_ret", rcaBeforeReturnRef.type); -:1349: } -:1350: } 302:1351: return rcaBeforeReturnRef; -:1352: } -:1353: -:1354: /// Returns: rtl.__sx_rc_dec (`function __sx_rc_dec(u8* array; u8* dtor; u32 elemBitSize): u8*`) -:1355: function rtl_rcaDecRefCount(): var FuncTyAndPtr -:1356: { 4644:1357: if !rcaDecRefCountRef.func do -:1358: { 98:1359: if isRtlRootUnit do -:1360: { 44:1361: const auto fd = unitNode.symbol.find(identifier("__sx_rc_dec")).symToFuncDecl(); 44:1362: if !fd.ir do visitFunctionDeclaration(fd); 44:1363: rcaDecRefCountRef.type = getTypeIr(fd.asTypeDeclared); 44:1364: rcaDecRefCountRef.func = nodeIRtoValueRef(fd); -:1365: } -:1366: else do -:1367: { 54:1368: rcaDecRefCountRef.type = LLVMFunctionType(rcaType, [rcaType, getPointerTypeIr(TypeU8.instance()), getTypeIr(TypeU32.instance())].ptr, 3, false); 54:1369: rcaDecRefCountRef.func = LLVMAddFunction(unitIr, "rtl.__sx_rc_dec", rcaDecRefCountRef.type); -:1370: } -:1371: } 4644:1372: return rcaDecRefCountRef; -:1373: } -:1374: -:1375: /// Returns: rtl.__sx_rc_dec (`function __sx_rc_dec(u8* array; u8 dims): u8*`) -:1376: function rtl_rcaDecRefCountNest(): var FuncTyAndPtr -:1377: { 24:1378: if !rcaDecRefCountNestRef.func do -:1379: { 5:1380: rcaDecRefCountNestRef.type = LLVMFunctionType(rcaType, [rcaType, getTypeIr(TypeU8.instance())].ptr, 2, false); 5:1381: rcaDecRefCountNestRef.func = LLVMAddFunction(unitIr, "rtl.__sx_rc_dec_nest", rcaDecRefCountNestRef.type); -:1382: } 24:1383: return rcaDecRefCountNestRef; -:1384: } -:1385: -:1386: /// Returns: rtl.__sx_rc_dup (`function __sx_rc_dup(u8* array; u32 elemBitSize): u8*`) -:1387: function rtl_rcaDup(): var FuncTyAndPtr -:1388: { 24:1389: if !rcaDupRef.func do -:1390: { 10:1391: rcaDupRef.type = LLVMFunctionType(rcaType, [rcaType, getTypeIr(TypeU32.instance())].ptr, 2, false); 10:1392: rcaDupRef.func = LLVMAddFunction(unitIr, "rtl.__sx_rc_dup", rcaDupRef.type); -:1393: } 24:1394: return rcaDupRef; -:1395: } -:1396: -:1397: /// Returns: rtl.__sx_rc_elemdtor (`function __sx_rc_elemdtor(u8* array; usize len0; usize len1; u32 elemBitSize; u8* dtorPtr): u8*`) -:1398: function rtl_rcaElemDtor(): var FuncTyAndPtr -:1399: { 14:1400: if !rcaElemDtorRef.func do -:1401: { 3:1402: var auto st = getTypeIr(TypeUSize()); 3:1403: var auto bt = getTypeIr(TypeU32.instance()); 3:1404: var auto pt = getPointerTypeIr(TypeU8.instance()); 3:1405: rcaElemDtorRef.type = LLVMFunctionType(getTypeIr(TypeVoid.instance()), [rcaType, st, st, bt, pt].ptr, 5, false); 3:1406: rcaElemDtorRef.func = LLVMAddFunction(unitIr, "rtl.__sx_rc_elemdtor", rcaElemDtorRef.type); -:1407: } 14:1408: return rcaElemDtorRef; -:1409: } -:1410: -:1411: /// Returns: rtl.__sx_rc_from_slice (`function __sx_rc_from_slice(u8* array; usize len; u32 elemBitSize): u8*`) -:1412: function rtl_rcaFromSlice(): var FuncTyAndPtr -:1413: { 474:1414: if !rcaFromSliceRef.func do -:1415: { 71:1416: if isRtlRootUnit do -:1417: { 44:1418: const auto fd = unitNode.symbol.find(identifier("__sx_rc_from_slice")).symToFuncDecl(); 44:1419: if !fd.ir do visitFunctionDeclaration(fd); 44:1420: rcaFromSliceRef.type = getTypeIr(fd.asTypeDeclared); 44:1421: rcaFromSliceRef.func = nodeIRtoValueRef(fd); -:1422: } -:1423: else do -:1424: { 27:1425: var auto pt = getPointerTypeIr(TypeU8.instance()); 27:1426: var auto lt = getTypeIr(TypeUSize()); 27:1427: var auto st = getTypeIr(TypeU32.instance()); 27:1428: rcaFromSliceRef.type = LLVMFunctionType(rcaType, [rcaType, pt, lt, st].ptr, 4, false); 27:1429: rcaFromSliceRef.func = LLVMAddFunction(unitIr, "rtl.__sx_rc_from_slice", rcaFromSliceRef.type); -:1430: } -:1431: } 474:1432: return rcaFromSliceRef; -:1433: } -:1434: -:1435: /// Returns: rtl.__sx_rc_get_length (`function __sx_rc_get_length(u8* array): usize`) -:1436: function rtl_rcaGetLength(): var FuncTyAndPtr -:1437: { 3998:1438: if !rcaGetLengthRef.func do -:1439: { 97:1440: if isRtlRootUnit do -:1441: { 44:1442: const auto fd = unitNode.symbol.find(identifier("__sx_rc_get_length")).symToFuncDecl(); 44:1443: if !fd.ir do visitFunctionDeclaration(fd); 44:1444: rcaGetLengthRef.type = getTypeIr(fd.asTypeDeclared); 44:1445: rcaGetLengthRef.func = nodeIRtoValueRef(fd); -:1446: } -:1447: else do -:1448: { 53:1449: rcaGetLengthRef.type = LLVMFunctionType(getTypeIr(TypeUSize()), &rcaType, 1, false); 53:1450: rcaGetLengthRef.func = LLVMAddFunction(unitIr, "rtl.__sx_rc_get_length", rcaGetLengthRef.type); -:1451: } -:1452: } 3998:1453: return rcaGetLengthRef; -:1454: } -:1455: -:1456: /// Returns: rtl.__sx_rc_inc (`function __sx_rc_inc(u8* array): u8*`) -:1457: function rtl_rcaIncRefCount(): var FuncTyAndPtr -:1458: { 1816:1459: if !rcaIncRefCountRef.func do -:1460: { 83:1461: if isRtlRootUnit do -:1462: { 44:1463: const auto fd = unitNode.symbol.find(identifier("__sx_rc_inc")).symToFuncDecl(); 44:1464: if !fd.ir do visitFunctionDeclaration(fd); 44:1465: rcaIncRefCountRef.type = getTypeIr(fd.asTypeDeclared); 44:1466: rcaIncRefCountRef.func = nodeIRtoValueRef(fd); -:1467: } -:1468: else do -:1469: { 39:1470: rcaIncRefCountRef.type = LLVMFunctionType(rcaType, &rcaType, 1, false); 39:1471: rcaIncRefCountRef.func = LLVMAddFunction(unitIr, "rtl.__sx_rc_inc", rcaIncRefCountRef.type); -:1472: } -:1473: } 1816:1474: return rcaIncRefCountRef; -:1475: } -:1476: -:1477: /// Returns: rtl.__sx_rc_get_ptr (function __sx_rc_get_ptr(u8* array): u8*) -:1478: function rtl_rcaPtr(): var FuncTyAndPtr -:1479: { 3492:1480: if !rcaPtrRef.func do -:1481: { 98:1482: if isRtlRootUnit do -:1483: { 44:1484: const auto fd = unitNode.symbol.find(identifier("__sx_rc_get_ptr")).symToFuncDecl(); 44:1485: if !fd.ir do visitFunctionDeclaration(fd); 44:1486: rcaPtrRef.type = getTypeIr(fd.asTypeDeclared); 44:1487: rcaPtrRef.func = nodeIRtoValueRef(fd); -:1488: } -:1489: else do -:1490: { 54:1491: rcaPtrRef.type = LLVMFunctionType(getPointerTypeIr(TypeU8.instance()), &rcaType, 1, false); 54:1492: rcaPtrRef.func = LLVMAddFunction(unitIr, "rtl.__sx_rc_get_ptr", rcaPtrRef.type); -:1493: } -:1494: } 3492:1495: return rcaPtrRef; -:1496: } -:1497: -:1498: /// Returns: rtl.__sx_rc_get_ref (`function __sx_rc_get_ref(u8* array): usize`) -:1499: function rtl_rcaRefCount(): var FuncTyAndPtr -:1500: { 92:1501: if !rcaRefCountRef.func do -:1502: { 5:1503: rcaRefCountRef.type = LLVMFunctionType(getTypeIr(TypeUSize()), &rcaType, 1, false); 5:1504: rcaRefCountRef.func = LLVMAddFunction(unitIr, "rtl.__sx_rc_get_ref", rcaRefCountRef.type); -:1505: } 92:1506: return rcaRefCountRef; -:1507: } -:1508: -:1509: /// Returns: rtl.__sx_rc_set_length (`function __sx_rc_set_length(u8* array; usize len; u32 elemBitSize): u8*`) -:1510: function rtl_rcaSetLength(): var FuncTyAndPtr -:1511: { 416:1512: if !rcaSetLengthRef.func do -:1513: { 77:1514: if isRtlRootUnit do -:1515: { 44:1516: const auto fd = unitNode.symbol.find(identifier("__sx_rc_set_length")).symToFuncDecl(); 44:1517: if !fd.ir do visitFunctionDeclaration(fd); 44:1518: rcaSetLengthRef.type = getTypeIr(fd.asTypeDeclared); 44:1519: rcaSetLengthRef.func = nodeIRtoValueRef(fd); -:1520: } -:1521: else do -:1522: { 33:1523: rcaSetLengthRef.type = LLVMFunctionType(rcaType, [rcaType, getTypeIr(TypeUSize()), getTypeIr(TypeU32.instance())].ptr, 3, false); 33:1524: rcaSetLengthRef.func = LLVMAddFunction(unitIr, "rtl.__sx_rc_set_length", rcaSetLengthRef.type); -:1525: } -:1526: } 416:1527: return rcaSetLengthRef; -:1528: } -:1529: -:1530: /// Sets the `.dbgIr` of a TypeRaw -:1531: function setBasicTypeDi(Type* type; DWARF_ENCODING encoding; LLVMDIFlags flags) -:1532: { 3113:1533: if !diGenerate do 2596:1534: return; 517:1535: var auto t = format(type); 517:1536: type.dbgIr = diBuilder.createBasicType(t, type.size, encoding, flags):u8*; 517:1537: } -:1538: -:1539: /// runtime "printf" to inspect oddities when generated code runs -:1540: version none do function runTimePrintf(s8[] specifier; LLVMValueRef[] args) -:1541: { -:1542: var auto s = instrBuilder.globalStringPtr(specifier); -:1543: instrBuilder.call(libc_printf().tupleof, s ~ args); -:1544: instrBuilder.call(libc_fflush().tupleof, [zerosize]); -:1545: } -:1546: -:1547: /// Sets the `.dbgIr` of a Type that has no simple C equivalent -:1548: function setUnspecifiedTypeDi(Type* type) -:1549: { 406:1550: if !diGenerate do 333:1551: return; 73:1552: var auto t = format(type); 73:1553: type.dbgIr = diBuilder.createUnspecifiedType(t):u8*; 73:1554: } -:1555: -:1556: /// Mark a node so that its `.ir` is reset once the unit finished -:1557: function setVisited(const AstNode* node) -:1558: { 82622:1559: visited.append(node); 82622:1560: } -:1561: -:1562: function startBlock(LLVMBasicBlockRef bb) -:1563: { 60805:1564: currentBlock = bb; 60805:1565: instrBuilder.positionAtEnd(bb); 60805:1566: } -:1567: -:1568: /// Returns: the struct type for an @llvm.global_ctors entry, i.e `type { i32, void ()*, i8* }` -:1569: function staticCtorEntryType(): LLVMTypeRef -:1570: { 113:1571: if !staticCtorDtorEntryType do -:1572: { 22:1573: const LLVMTypeRef voidFuncPtrT = LLVMPointerType(LLVMFunctionType(getTypeIr(TypeVoid.instance()), null, 0, false), 0); 22:1574: const LLVMTypeRef[3] ts = [getTypeIr(TypeU32.instance()), voidFuncPtrT, getPointerTypeIr(TypeU8.instance())]; 22:1575: staticCtorDtorEntryType = LLVMStructTypeInContext(ctxt, ts.ptr, 3, false); -:1576: } 113:1577: return staticCtorDtorEntryType; -:1578: } -:1579: 282:1580: function success(): bool {return successFlag;} -:1581: -:1582: /// special processing for @LLVM functions -:1583: function tryLLVMIntrinsicDeclaration(FunctionDeclaration* node): bool -:1584: { 128305:1585: if FunctionFlag.isLLVM !in node.flags do 128277:1586: return false; -:1587: 28:1588: visited.append(node); 28:1589: node.progress = irgened; -:1590: 28:1591: visitConcreteType(node.returnType); 28:1592: var auto a = node.getAtLLVM(); 28:1593: const s8[] name = a.arguments.length != 0 ? asStringExp(a.arguments[0]).value.text()[] else node.name.text()[]; 28:1594: const s8[] fqn = "llvm."[] ~ name ~ "\0"; 28:1595: const u32 id = LLVMLookupIntrinsicID(fqn.ptr, fqn.length - 1); 28:1596: if id == 0 do -:1597: { 1:1598: error(node.scope.filename, node.startPos, "invalid intrinsic ID for `%s`. Check https://llvm.org/docs/LangRef.html#intrinsic-functions", fqn.ptr); 0:1599: exit(1); -:1600: } 27:1601: const u32 np = node.parameters.length:u32; 72:1602: alias fun = function[T](T t): LLVMTypeRef => {visitConcreteType(t.type); return getTypeIr(t.type);}; 27:1603: var auto pt = map:[fun](node.parameters); 27:1604: var auto rt = getTypeIr(node.returnType); -:1605: -:1606: // Note : `LLVMGetIntrinsicDeclaration` is the official way to retieve a decl -:1607: // but caused problems with certain overloaded instrinsics because it requires -:1608: // to know what is overloaded (return ? param 0 ? param 1 ? ...) -:1609: // -:1610: // While not documented, `LLVMAddFunction` can also be used and seems even -:1611: // better as it is able to auto-detect what is actually overloaded 27:1612: var auto ft = LLVMFunctionType(rt, pt.ptr, np, FunctionFlag.isCeeVariadic in node.flags); 27:1613: node.ir = LLVMAddFunction(unitIr, fqn.ptr, ft):u8*; 27:1614: setTypeIr(node.asTypeDeclared, ft, null); -:1615: 27:1616: assert(node.ir, "bad LLVM instrinsic name"); 27:1617: return true; -:1618: } -:1619: -:1620: @override function visitAddAssignExpression(const AddAssignExpression* node) -:1621: { 190:1622: visitBinaryAssignExpression(node); 190:1623: } -:1624: -:1625: @override function visitAddExpression(const AddExpression* node) -:1626: { 841:1627: visitBinaryExpression(node); 841:1628: } -:1629: 256:1630: @override function visitAliasDeclaration(const AliasDeclaration* node){} -:1631: -:1632: @override function visitApplyExpression(ApplyExpression* node) -:1633: { 302:1634: node.accept(this); 604:1635: if pass == 1 do visitIdentExpression(node.application); 302:1636: } -:1637: -:1638: @override function visitAndAndExpression(AndAndExpression* node) -:1639: { 867:1640: var auto andAndBr = instrBuilder.appendBasicBlock(currentFunction); 867:1641: var auto andAndEndBr = instrBuilder.appendBasicBlock(currentFunction); -:1642: var LLVMBasicBlockRef actualAndAndBr; -:1643: 867:1644: resetAndVisitExp(node.left); 867:1645: loadExpIfLvalue(node.left); 867:1646: var auto startBr = currentBlock; 867:1647: var LLVMValueRef v1 = exp; 867:1648: instrBuilder.condBr(v1, andAndBr, andAndEndBr); -:1649: 867:1650: startBlock(andAndBr); 867:1651: var auto p = node.right.startPos; 867:1652: if doCover && p.line != node.startPos.line do 1:1653: cover(p); 867:1654: resetAndVisitExp(node.right); 867:1655: loadExpIfLvalue(node.right); 867:1656: actualAndAndBr = currentBlock; 867:1657: var auto v2 = exp; 867:1658: instrBuilder.br(andAndEndBr); -:1659: 867:1660: startBlock(andAndEndBr); 867:1661: exp = instrBuilder.phi(getTypeIr(TypeBool.instance())); 867:1662: instrBuilder.addIncoming(exp, [v1, v2], [startBr, actualAndAndBr]); 867:1663: } -:1664: -:1665: @override function visitAndAssignExpression(const AndAssignExpression* node) -:1666: { 6:1667: visitBinaryAssignExpression(node); 6:1668: } -:1669: -:1670: @override function visitAndExpression(const AndExpression* node) -:1671: { 23:1672: visitBinaryExpression(node); 23:1673: } -:1674: -:1675: @override function visitArrayExpression(ArrayExpression* node) -:1676: { 279:1677: visitConcreteType(node.type); 279:1678: var auto tsa = node.type.asTypeStaticArray(); -:1679: -:1680: // e.g empty array returned from echo(getUnittests) 279:1681: if node.items.length == 0 do -:1682: { 1:1683: var auto g = LLVMAddGlobal(unitIr, getTypeIr(tsa), ""); 1:1684: exp = constBuilder.array(getTypeIr(tsa.modified), []); 1:1685: LLVMSetInitializer(g, exp); 1:1686: exp = g; 1:1687: return; -:1688: } -:1689: 278:1690: if node.asLvalue do 214:1691: currentArrayExp = nodeIRtoValueRef(node.asLvalue); 278:1692: if !node.isStaticallyEvaluable do -:1693: { 78:1694: const auto t = getTypeIr(tsa); 78:1695: foreach (const auto i; const auto e) in node.items do -:1696: { 139:1697: var auto o = currentArrayExp; 139:1698: var auto j = constBuilder.int(getTypeIr(TypeU32.instance()), i, false); 139:1699: var auto p = currentArrayExp = instrBuilder.gep(t, currentArrayExp, [zero32, j]); 139:1700: resetAndVisitExp(e); 139:1701: rcaIncrement(e, exp); 139:1702: if !asArrayExp(e) do 136:1703: instrBuilder.store(loadExpIfLvalue(e), p); 139:1704: currentArrayExp = o; -:1705: } 78:1706: exp = instrBuilder.load(getTypeIr(node.type), currentArrayExp); -:1707: } -:1708: else do -:1709: { 200:1710: var auto items = (new LLVMValueRef[+])(node.items.length); 200:1711: foreach (const auto i; const auto e) in node.items do -:1712: { 45505:1713: resetAndVisitExp(e); 45505:1714: items.ptr[i] = loadExpIfLvalue(e); -:1715: } 200:1716: exp = constBuilder.array(getTypeIr(tsa.modified), items); -:1717: } 278:1718: } -:1719: -:1720: @override function visitAsmExpression(AsmExpression* node) -:1721: { 13:1722: var s8[] asmSource = node.code ? node.code.text()[] else ""[]; 13:1723: var s8[] constraint = node.constraint ? node.constraint.text()[] else ""[]; -:1724: 13:1725: visitConcreteType(node.type); 13:1726: var auto rt = getTypeIr(node.type); -:1727: 13:1728: var auto pt = (new LLVMTypeRef[+])(node.arguments.length); 13:1729: var auto args = (new LLVMValueRef[+])(node.arguments.length); 13:1730: foreach (const auto i; const auto e) in node.arguments do -:1731: { 7:1732: args.ptr[i] = resetAndVisitExp(e); 7:1733: pt.ptr[i] = getTypeIr(e.type); -:1734: } -:1735: 13:1736: var auto proto = LLVMFunctionType(rt, pt.ptr, pt.length:u32, false); 13:1737: exp = LLVMGetInlineAsm(proto, asmSource.ptr, asmSource.length, -:1738: constraint.ptr, constraint.length, -:1739: 0, 0, currentAsmDialect); -:1740: 13:1741: exp = instrBuilder.call(proto, exp, args); 13:1742: } -:1743: -:1744: @override function visitAssertStatement(AssertStatement* node) -:1745: { 1548:1746: const bool isAssertz = node.flow.isReturn(); 1548:1747: const bool allAssert = AdditionalCheck.asserts in session.additionalChecks; 1548:1748: if !isAssertz && !allAssert do 41:1749: return; -:1750: 1507:1751: if isAssertz && session.gcov do -:1752: { 1:1753: session.generateDebugInfo = false; 1:1754: diGenerate = false; -:1755: } -:1756: 1550:1757: if doCover && !isAssertz do cover(node.startPos); -:1758: 1507:1759: assertSpecifier ?= instrBuilder.globalStringPtr(unitNode.scope.filename ~ ":%d:%d: runtime error, assert failure, `%s`\n\0"); 1507:1760: var auto lineCol = getLineCol(node.expression.startPos); -:1761: -:1762: var LLVMValueRef msg; -:1763: 1507:1764: if !isAssertz do -:1765: { 1249:1766: var auto passBr = instrBuilder.appendBasicBlock(currentFunction); 1249:1767: var auto failBr = instrBuilder.appendBasicBlock(currentFunction); -:1768: 1249:1769: resetAndVisitExp(node.expression); 1249:1770: loadExpIfLvalue(node.expression); 1249:1771: instrBuilder.condBr(exp, passBr, failBr); -:1772: 1249:1773: startBlock(failBr); 1249:1774: resetAndVisitExp(node.message); 1249:1775: msg = loadExpIfLvalue(node.message); 1249:1776: generateCheckFail([assertSpecifier, lineCol[0], lineCol[1], msg]); -:1777: 1249:1778: startBlock(passBr); -:1779: } -:1780: else do -:1781: { 258:1782: if node.message do -:1783: { 19:1784: resetAndVisitExp(node.message); 19:1785: msg = loadExpIfLvalue(node.message); -:1786: } 258:1787: if !msg do -:1788: { 239:1789: instrBuilder.call(llvm_trap().tupleof, []); 239:1790: instrBuilder.unreachable(); -:1791: } 19:1792: else do generateCheckFail([assertSpecifier, lineCol[0], lineCol[1], msg]); 258:1793: if session.gcov do -:1794: { 1:1795: session.generateDebugInfo = true; 1:1796: diGenerate = true; -:1797: } -:1798: } 1507:1799: } -:1800: -:1801: @override function visitAssignExpression(AssignExpression* node) -:1802: { 10834:1803: if var auto ie = asIndexExp(node.left) do -:1804: { 243:1805: if ie.arrayType.kind == tkEnumSet do -:1806: { 31:1807: var auto act = resetAndVisitExp(node.right); 31:1808: act = loadExpIfLvalue(node.right); 31:1809: var auto ptr = resetAndVisitExp(ie.expression); 31:1810: var auto val = instrBuilder.load(getTypeIr(ie.expression.type), ptr); 31:1811: var auto mbr = resetAndVisitExp(ie.indexes[0]); 31:1812: mbr = loadExpIfLvalue(ie.indexes[0]); 31:1813: enumSetIncludeOrExclude(ptr, val, mbr, act); 31:1814: exp = act; 31:1815: return; -:1816: } -:1817: } 5386:1818: resetAndVisitExp(node.right); 5386:1819: var auto rhs = loadExpIfLvalue(node.right); 10772:1820: if var TupleExpression* te = asTupleExp(node.left) do -:1821: { 16:1822: return visitTupleDeconstruction(te, rhs); -:1823: } 5370:1824: var auto lhs = resetAndVisitExp(node.left); 5370:1825: rcaDecrement(node.left, lhs); 5370:1826: aggregateDtor(node.left.type, lhs, node.left); 5370:1827: var auto e = instrBuilder.store(rhs, lhs); 5370:1828: instructionDi(node, e); 5370:1829: rcaIncrement(node.left, lhs); 5370:1830: } -:1831: -:1832: @override function visitAtExpression(AtExpression* node) -:1833: { 1037:1834: visitConcreteType(node.type); -:1835: // & means "dont load the lvalue" 1037:1836: resetAndVisitExp(node.expression); 1037:1837: } -:1838: 1:1839: @override function visitAttribute(const Attribute* node){ } -:1840: -:1841: function visitBinaryAssignExpression(AssignExpression* node) -:1842: { 396:1843: var auto ptr = resetAndVisitExp(node.left); 396:1844: resetAndVisitExp(node.right); 396:1845: var auto rhs = loadExpIfLvalue(node.right); 396:1846: var auto lhs = instrBuilder.load(getTypeIr(node.left.type), ptr); -:1847: 396:1848: const auto t0 = node.left.type.resolved(); 396:1849: const auto t1 = node.right.type.resolved(); 396:1850: const auto isFpOp = t0.isFloating(); 396:1851: const auto isSign = t0.isSigned() || t1.isSigned(); 396:1852: const auto isPtr = t0.kind == mul; 396:1853: const auto isSet = t0.kind == tkEnumSet; 396:1854: const auto isSet2 = t1.kind == tkEnumSet; -:1855: 396:1856: if isSet do -:1857: { 106:1858: if isSet2 do -:1859: { 9:1860: if node.operator == TokenType.minusAss do -:1861: { 5:1862: var auto neg = instrBuilder.xor(rhs, constBuilder.int(LLVMTypeOf(rhs), u64.max, false)); 5:1863: instrBuilder.store(instrBuilder.and(lhs, neg), ptr); -:1864: } 4:1865: else do instrBuilder.store(instrBuilder.or(lhs, rhs), ptr); -:1866: } -:1867: else do -:1868: { 97:1869: var auto v = node.operator == TokenType.plusAss ? enumsetInclude(lhs, rhs) else enumsetExclude(lhs, rhs); 97:1870: instrBuilder.store(v, ptr); -:1871: } 106:1872: exp = ptr; 106:1873: return; -:1874: } 290:1875: else do if isPtr do -:1876: { 49:1877: if node.operator == TokenType.minusAss do 45:1878: rhs = instrBuilder.neg(rhs); 49:1879: exp = instrBuilder.gep(getTypeIr(asTypePointer(node.left.type).modified), lhs, [rhs]); 49:1880: instrBuilder.store(exp, ptr); 49:1881: exp = ptr; 49:1882: return; -:1883: } -:1884: -:1885: var BinOpFun binFun; 241:1886: switch node.operator do -:1887: { 6:1888: on TokenType.mulAss do binFun = isFpOp ? &instrBuilder.fmul else &instrBuilder.mul; 48:1889: on TokenType.divAss do binFun = isFpOp ? &instrBuilder.fdiv else isSign ? &instrBuilder.sdiv else &instrBuilder.udiv; 2:1890: on TokenType.modAss do binFun = isFpOp ? &instrBuilder.frem else isSign ? &instrBuilder.srem else &instrBuilder.urem; 109:1891: on TokenType.plusAss do binFun = isFpOp ? &instrBuilder.add else &instrBuilder.add; 54:1892: on TokenType.minusAss do binFun = isFpOp ? &instrBuilder.fsub else &instrBuilder.sub; 6:1893: on TokenType.ampAss do binFun = &instrBuilder.and; 7:1894: on TokenType.pipeAss do binFun = &instrBuilder.or; 2:1895: on TokenType.lshiftAss do binFun = &instrBuilder.shl; 2:1896: on TokenType.rshiftAss do binFun = &instrBuilder.shr; 5:1897: on TokenType.xorAss do binFun = &instrBuilder.xor; -:1898: } -:1899: 241:1900: rhs = binFun(instrBuilder, lhs, rhs); 241:1901: instructionDi(node, rhs); 241:1902: node.ir = rhs:u8*; 241:1903: instrBuilder.store(rhs, ptr); 241:1904: exp = ptr; 241:1905: } -:1906: -:1907: @override function visitBinaryExpression(BinaryExpression* node) -:1908: { 2129:1909: resetAndVisitExp(node.right); 2129:1910: var auto rhs = loadExpIfLvalue(node.right); -:1911: 2129:1912: resetAndVisitExp(node.left); 2129:1913: var auto lhs = loadExpIfLvalue(node.left); -:1914: 2129:1915: const auto t0 = node.left.type.resolved(); 2129:1916: const auto t1 = node.right.type.resolved(); 2129:1917: const bool isFpOp = t0.isFloating(); 2129:1918: const bool isSign = t0.isSigned() || t1.isSigned(); 2129:1919: const auto isPtr = asTypePointer(t0); 2129:1920: const bool isSet = t0.kind == tkEnumSet; 2129:1921: const bool isSet2 = t1.kind == tkEnumSet; -:1922: 2129:1923: if isSet do -:1924: { 6:1925: if isSet2 do -:1926: { 4:1927: if node.operator == TokenType.minus do -:1928: { 2:1929: var auto neg = instrBuilder.xor(rhs, constBuilder.int(LLVMTypeOf(rhs), u64.max, false)); 2:1930: exp = instrBuilder.and(lhs, neg); -:1931: } 2:1932: else do exp = instrBuilder.or(lhs, rhs); -:1933: } 2:1934: else do exp = node.operator == TokenType.plus ? enumsetInclude(lhs, rhs) else enumsetExclude(lhs, rhs); 6:1935: return; -:1936: } 2123:1937: else do if isPtr do -:1938: { 153:1939: if node.type.isIntegral() do -:1940: { 4:1941: if node.operator == TokenType.minus do -:1942: { 3:1943: exp = instrBuilder.ptrDiff(getTypeIr(isPtr.modified), lhs, rhs); -:1944: } -:1945: else do -:1946: { 1:1947: lhs = instrBuilder.ptrToInt(lhs, getTypeIr(TypeUSize())); 1:1948: rhs = instrBuilder.ptrToInt(rhs, getTypeIr(TypeUSize())); 1:1949: exp = instrBuilder.add(lhs, rhs); -:1950: } 4:1951: exp = instrBuilder.ptrToInt(exp, getTypeIr(node.type)); -:1952: } -:1953: else do -:1954: { 149:1955: if node.operator == TokenType.minus do 3:1956: rhs = instrBuilder.neg(rhs); 149:1957: exp = instrBuilder.gep(getTypeIr(asTypePointer(node.left.type).modified), lhs, [rhs]); -:1958: } 153:1959: return; -:1960: } -:1961: -:1962: var BinOpFun binFun; 1970:1963: switch node.operator do -:1964: { 347:1965: on TokenType.mul do binFun = isFpOp ? &instrBuilder.fmul else &instrBuilder.mul; 274:1966: on TokenType.div do binFun = isFpOp ? &instrBuilder.fdiv else isSign ? &instrBuilder.sdiv else &instrBuilder.udiv; 59:1967: on TokenType.mod do binFun = isFpOp ? &instrBuilder.frem else isSign ? &instrBuilder.srem else &instrBuilder.urem; 691:1968: on TokenType.plus do binFun = isFpOp ? &instrBuilder.fadd else &instrBuilder.add; 504:1969: on TokenType.minus do binFun = isFpOp ? &instrBuilder.fsub else &instrBuilder.sub; 23:1970: on TokenType.amp do binFun = &instrBuilder.and; 51:1971: on TokenType.pipe do binFun = &instrBuilder.or; 8:1972: on TokenType.lShift do binFun = &instrBuilder.shl; 9:1973: on TokenType.rShift do binFun = &instrBuilder.shr; 4:1974: on TokenType.xor do binFun = &instrBuilder.xor; -:1975: } 1970:1976: exp = binFun(instrBuilder, lhs, rhs); 1970:1977: instructionDi(node, exp); 1970:1978: } -:1979: -:1980: @override function visitBlockStatement(BlockStatement* node) -:1981: { 11811:1982: var auto oldDiScope = diScope; -:1983: 11811:1984: if diGenerate do 6613:1985: diScope = diBuilder.createLexicalBlock(diScope, node.startPos.line, node.startPos.column); -:1986: -:1987: // initialize temporaries that can be referenced for cleanup but never initialized -:1988: // e.g `__temp` in `if a && (var auto __temp = call()).length do ...` is not init -:1989: // if `a` is false 11811:1990: foreach const auto vd in node.managedLocals do -:1991: { 1364:1992: if VariableFlag.isTemp in vd.flags do -:1993: { -:1994: //printf("visit temp %s on BlockStatement entry\n", vd.name.text().ptr); 796:1995: visitVariableDeclaration(vd); -:1996: } -:1997: } -:1998: 71739:1999: each:[function[S](S s) => visitStatement(s)](node.statements); 11811:2000: if node.flow.isContinueToNext() do 5015:2001: freeManagedLocals(node, node.managedLocals); 11811:2002: diScope = oldDiScope; 11811:2003: } -:2004: -:2005: @override function visitBoolExpression(const BoolExpression* node) -:2006: { 1510:2007: exp = constBuilder.int(getTypeIr(TypeBool.instance()), node.value, false); 1510:2008: } -:2009: -:2010: @override function visitBreakOnStatement(BreakOnStatement* node) -:2011: { 6:2012: freeManagedLocals(node, node.managedLocals); 6:2013: if doCover do cover(node.startPos); 6:2014: exp = instrBuilder.br(nodeIRtoBlockRef(node)); 6:2015: instructionDi(node, exp); 6:2016: } -:2017: -:2018: @override function visitBreakStatement(BreakStatement* node) -:2019: { 771:2020: if node.expression do resetAndVisitExp(node.expression); 717:2021: if doCover do cover(node.startPos); 652:2022: freeManagedLocals(node, node.managedLocals); 652:2023: if !node.$label do -:2024: { 649:2025: var auto lbr = node.target.ir:LoopBlockRefIr*; 649:2026: exp = instrBuilder.br(lbr.breakBr); -:2027: } -:2028: else do -:2029: { 3:2030: assert (node.symbol.astNode.ir); 3:2031: var auto bir = node.symbol.astNode.ir:LoopBlockRefIr*; 3:2032: exp = instrBuilder.br(bir.breakBr); -:2033: } 652:2034: instructionDi(node, exp); 652:2035: } -:2036: -:2037: @override function visitCallExpression(CallExpression* node) -:2038: { 10500:2039: visitConcreteExpression(node.expression); -:2040: // exp is a lvalue in case of func ptr only 10500:2041: var auto callee = loadExpIfLvalue(node.expression); 10500:2042: var auto fd = getFuncDeclForCall(node); -:2043: -:2044: var LLVMValueRef thisArg; 10500:2045: if node.checkThis do -:2046: { 2942:2047: thisArg = resetAndVisitExp(node.arguments[0]); 2942:2048: var auto thisArgLd = loadExpIfLvalue(node.arguments[0]); 2942:2049: nullthisSpecifier ?= instrBuilder.globalStringPtr(unitNode.filename ~ ":%d:%d: runtime error, member function called with null `this`\n\0"); 2942:2050: checkNull(node.expression.startPos, thisArgLd, nullthisSpecifier); -:2051: } -:2052: 10500:2053: const auto alen = node.arguments.length; 10500:2054: const auto plen = fd.parameters.length; 10500:2055: var auto args = (new LLVMValueRef[+])(alen); 10500:2056: foreach const auto i in 0 .. alen do -:2057: { 17935:2058: var auto p = i < plen ? fd.parameters.ptr[i] else null; 17935:2059: var auto a = node.arguments.ptr[i]; 17935:2060: const auto reachedVariadic = i >= plen; 17935:2061: if thisArg do -:2062: { 2942:2063: exp = thisArg; 2942:2064: thisArg = null; -:2065: } 14993:2066: else do resetAndVisitExp(a); 17935:2067: const auto isVar = p && p.isVar(); 17935:2068: if a.isLvalue() && ((p && !isVar) || reachedVariadic) do 9050:2069: exp = instrBuilder.load(getTypeIr(a.type), exp); 17935:2070: args.ptr[i] = exp; -:2071: } 10500:2072: assert(fd.asTypeDeclared && fd.asTypeDeclared.ir); 10500:2073: if fd.virtualIndex != -1 && !node.isDevirtualized do -:2074: { 800:2075: var auto ta = asTypeAggregate(fd.parameters.ptr[0].type.asTypePointer().modified); 800:2076: var auto ad = ta.declaration; 800:2077: var auto vtty = ad.vtableVar.type; 800:2078: var auto ftpe = LLVMTypeOf(callee); 800:2079: var auto vidx = constBuilder.int(getTypeIr(TypeU32.instance()), fd.virtualIndex + 1, false); 800:2080: callee = instrBuilder.structGep(getTypeIr(ta), args.ptr[0], 0); 800:2081: callee = instrBuilder.load(getTypeIr(vtty), callee); 800:2082: callee = instrBuilder.gep(getTypeIr(asTypePointer(vtty).modified), callee, [zero32, vidx]); 800:2083: callee = instrBuilder.load(ftpe, callee); -:2084: } 10500:2085: assert(callee); 10500:2086: exp = instrBuilder.call(getTypeIr(fd.asTypeDeclared), callee, args); 10500:2087: instructionDi(node, exp); -:2088: -:2089: // use the ctor `this` argument as result -:2090: // either as pointer or as value-type lvalue -:2091: // since value-type ctors allocate a temporary 10500:2092: if FunctionFlag.isCtor in fd.flags do 685:2093: exp = args[0]; -:2094: 10500:2095: if node.arguments.length do -:2096: { -:2097: // opt access can be hidden due to a static cast to a base class 9701:2098: var auto ce = asCastExp(node.arguments[0]); 19402:2099: if var auto oae = asOptAccessExp(ce ? ce.expression else node.arguments[0]) do 113:2100: optAccessFinalize(oae); -:2101: } 10500:2102: } -:2103: -:2104: @override function visitCastExpression(CastExpression* node) -:2105: { 11140:2106: const bool isSigned = node.expression.type.isSigned(); 11140:2107: const bool isNullCast = node.expression.operator == TokenType.$null; 11140:2108: visitConcreteType(node.toType); 21074:2109: if !isNullCast do visitConcreteExpression(node.expression); 11140:2110: loadExpIfLvalue(node.expression); 11140:2111: var auto castToTy = getTypeIr(node.toType); -:2112: 11140:2113: switch node.kind do -:2114: { 4121:2115: on intExt do exp = isSigned ? instrBuilder.sext(exp, castToTy) else instrBuilder.zext(exp, castToTy); 5:2116: on fpExt do exp = instrBuilder.fpExt(exp, castToTy); 16:2117: on intToFp do exp = isSigned ? instrBuilder.siToFp(exp, castToTy) else instrBuilder.uiToFp(exp, castToTy); 1426:2118: on nullCast do exp = nullPtr; 3:2119: on staToPtr do exp = instrBuilder.bitCast(exp, castToTy); 1557:2120: on intTrunc do exp = instrBuilder.trunc(exp, castToTy); 4:2121: on fpTrunc do exp = instrBuilder.fpTrunc(exp, castToTy); 6:2122: on fpToInt do exp = node.toType.isSigned() ? instrBuilder.fpToSi(exp, castToTy) else instrBuilder.fpToUi(exp, castToTy); 3945:2123: on bitCast do exp = instrBuilder.bitCast(exp, castToTy); 3:2124: on ptrCast do exp = instrBuilder.pointerCast(exp, castToTy); 4:2125: on intToPtr do exp = instrBuilder.intToPtr(exp, castToTy); 1:2126: on strToSta do exp = instrBuilder.load(castToTy, instrBuilder.bitCast(exp, LLVMPointerType(castToTy,0))); 3:2127: on voidCast do exp = null; -:2128: on dynCastP do -:2129: { 46:2130: var auto tc2 = node.toType.asTypePointer().modified.asTypeClass(); 46:2131: var auto u8Ptr = getPointerTypeIr(TypeU8.instance()); 46:2132: var auto vt = nodeIRtoValueRef(tc2.declaration.vtableVar); 46:2133: vt = instrBuilder.bitCast(vt, u8Ptr); 46:2134: exp = instrBuilder.call(rtl_dyncast().tupleof, [exp, vt], "dyncast"); 46:2135: instructionDi(node, exp); 46:2136: exp = instrBuilder.bitCast(exp, castToTy); -:2137: } -:2138: else do assert(0); -:2139: } -:2140: //instructionDi(node, exp); 11140:2141: } -:2142: -:2143: @override function visitClassDeclaration(ClassDeclaration* node) -:2144: { 19970:2145: if node.nextInstance do 7:2146: visitConcreteDeclaration(node.nextInstance); 19970:2147: if node.isGeneric() do 3:2148: return; 19967:2149: const DeclModuleInfo di = getDeclModuleInfo(node); 19967:2150: if di.isVisited do -:2151: { -:2152: //printf("skip visit of aggregate %s in unit %s\n", node.name.text().ptr, unitNode.scope.filename.ptr); 15496:2153: return; -:2154: } -:2155: //printf("visiting aggregate %s in unit %s\n", node.name.text().ptr, unitNode.scope.filename.ptr); -:2156: 4471:2157: if node.symbol.recurseGuard do 0:2158: return; 4471:2159: node.symbol.recurseGuard++; -:2160: 4471:2161: var s8[+] linkageName = node.linkageName; 4471:2162: var auto oldAggregateType = currentAggregateType; 4471:2163: currentAggregateType = LLVMStructCreateNamed(ctxt, (linkageName ~ "\0").ptr); 4471:2164: node.ir = currentAggregateType:u8*; -:2165: // Set a partial type IR, e.g if the body contains variable that are pointers/array of this type 4471:2166: setTypeIr(node.symbol.asType(), currentAggregateType, constBuilder.zeroInit(currentAggregateType)); -:2167: // If the matching TypeClass is never visited explictly, mark it for reset here 4471:2168: setVisited(node.symbol.asType()); -:2169: -:2170: var LLVMTypeRef[+] membersT; -:2171: // add vtable type and super vtable type 4471:2172: if node.body do -:2173: { 4470:2174: visitConcreteType(node.vtableVar.type); 4470:2175: membersT = [getTypeIr(node.vtableVar.type)]; 4470:2176: vtableOwners.append(node); -:2177: } -:2178: -:2179: var Type*[+] chain; 4471:2180: getInheritanceChain(node.asTypeDeclared, chain); -:2181: -:2182: // add inherited member types 4471:2183: const u8 oldPass = pass; 4471:2184: var auto mtc = membersT.length; 4471:2185: foreach const auto t in chain do -:2186: { 15797:2187: var auto tc = asTypeClass(t); 15797:2188: pass = 0; 15797:2189: visitClassDeclaration(tc.declaration); 15797:2190: visitTypeClass(tc); 15797:2191: pass = oldPass; 31594:2192: if const auto len = tc.declaration.symbol.children.length do -:2193: { 15785:2194: membersT.length += len; 15785:2195: foreach const auto c in tc.declaration.symbol.children.ptr[0 .. len] do -:2196: { 103732:2197: var auto vd = symToVarDecl(c); 103732:2198: if !vd || vd:u8* == tc.declaration.vtableVar:u8* do 68974:2199: continue; 34758:2200: pass = 0; 34758:2201: visitVariableDeclaration(vd); 34758:2202: pass = oldPass; 34758:2203: var auto vt = vd.type.resolved(); 34758:2204: var auto pt = vt.asTypePointer(); 34758:2205: var auto tc2 = pt ? pt.modified.asTypeClass() else null; 34758:2206: if vd.isStatic() do 4:2207: continue; 34754:2208: if tc2 && tc2.declaration.symbol.recurseGuard do 564:2209: membersT.ptr[mtc++] = LLVMPointerType(tc2.declaration.ir:LLVMTypeRef, 0); -:2210: else do 34190:2211: membersT.ptr[mtc++] = getTypeIr(vd.type); -:2212: } -:2213: } -:2214: } -:2215: 4471:2216: pass = 0; 8941:2217: if node.body do visitDeclarations(node.body); 4471:2218: pass = oldPass; -:2219: 8942:2220: if const auto len = node.symbol.children.length do -:2221: { 4446:2222: membersT.length += len; 4446:2223: foreach var auto c in node.symbol.children do -:2224: { 26537:2225: var auto vd = symToVarDecl(c); 26537:2226: if !vd || vd.isStatic() do 18525:2227: continue; 8012:2228: membersT.ptr[mtc++] = getTypeIr(vd.type); -:2229: } -:2230: } 4471:2231: membersT.length = mtc; -:2232: 4471:2233: LLVMStructSetBody(currentAggregateType, membersT.ptr, membersT.length:u32, false); -:2234: 4471:2235: if node.body do -:2236: { -:2237: // "non-overriden-methods" that are not used need an extern decl too. -:2238: // E.g: Base is in an import, Derived is in current unit but no all -:2239: // Base methods are overridden. The Derived vtable need an address. -:2240: // It is obtained by generating an IR, like if the func was used. 4470:2241: foreach const auto fd in node.vtable do 43059:2242: if isImported(fd) do -:2243: { 40971:2244: visitFunctionDeclaration(fd); -:2245: // dont add to the `functions` array because this array is designed -:2246: // to visit bodies during the 2nd pass but here we know that the body -:2247: // does not need to be ir-gen'd 40971:2248: functions2.append(fd); -:2249: } -:2250: -:2251: // Generate a globals for the vtable. The initializer is set after the function pass. 4470:2252: var auto u8PtrIr = getPointerTypeIr(TypeU8.instance()); 4470:2253: var auto vtableType = LLVMArrayType(u8PtrIr, (node.vtable.length + 1):u32); 4470:2254: var auto thisVtableIr = LLVMAddGlobal(unitIr, vtableType, (linkageName ~ ".vtable\0").ptr); -:2255: //printf("create global for %s vtable in %s\n", node.name.text().ptr, unitNode.scope.filename.ptr); 4470:2256: node.vtableVar.ir = thisVtableIr:u8*; -:2257: -:2258: // compute the default init 4470:2259: var usize mc = 1; 4470:2260: var LLVMValueRef[+] members = [thisVtableIr]; 4470:2261: chain ~= node.asTypeDeclared; 4470:2262: foreach const auto t in chain do -:2263: { 20266:2264: var auto tc = asTypeClass(t); 40532:2265: if const auto len = tc.declaration.symbol.children.length do -:2266: { 20230:2267: members.length += len; 20230:2268: foreach const auto c in tc.declaration.symbol.children do -:2269: { 130268:2270: var auto vd = symToVarDecl(c); 130268:2271: if !vd || vd:u8* == tc.declaration.vtableVar:u8* do 86975:2272: continue; 43293:2273: var auto vt = vd.type.resolved(); 43293:2274: var auto pt = vt.asTypePointer(); 43293:2275: var auto tc2 = pt ? pt.modified.asTypeClass() else null; 43293:2276: if vd.isStatic() do 527:2277: continue; 42766:2278: if tc2 && tc2.declaration.symbol.recurseGuard do 877:2279: members.ptr[mc++] = nullPtr; -:2280: else do 41889:2281: members.ptr[mc++] = getInitializer(vd); -:2282: } -:2283: } -:2284: } 4470:2285: members.length = mc; -:2286: -:2287: // Store the real initializer. 4470:2288: var auto def = constBuilder.namedStruct(currentAggregateType, members); 4470:2289: var auto t = node.symbol.asType(); 4470:2290: setTypeIr(t, currentAggregateType, def); -:2291: 4470:2292: if diGenerate do -:2293: { 4305:2294: var auto baseIr = node.inheritanceList.length ? asTypeClass(node.inheritanceList[0]).dbgIr:LLVMMetadataRef else null; 4305:2295: var auto diMembers = getMemberDi(node.symbol); 8281:2296: if baseIr do diMembers ~= diBuilder.createInheritance(baseIr); 4305:2297: t.dbgIr = diBuilder.createClassType(diUnitRef, linkageName, -:2298: node.startPos.line, t.size, t.align, LLVMDIFlags.Zero, baseIr, diMembers):u8*; -:2299: } -:2300: } -:2301: 4471:2302: node.symbol.recurseGuard--; 4471:2303: currentAggregateType = oldAggregateType; 4471:2304: } -:2305: -:2306: @override function visitCmpExpression(CmpExpression* node) -:2307: { 6652:2308: const bool isDyna = node.buitlinCmpType == tkSlice; 6652:2309: if node.buitlinCmpType == TokenType.$struct || node.buitlinCmpType == tkSta || isDyna || node.buitlinCmpType == comma do -:2310: { 118:2311: var auto tsl = asTypeSlice(node.left.type); 118:2312: const auto bsz = tsl ? tsl.modified.resolved().size else node.left.type.resolved().size; -:2313: -:2314: var LLVMBasicBlockRef lenNeBr; -:2315: var LLVMBasicBlockRef lenEqBr; -:2316: var LLVMBasicBlockRef ptrEqBr; -:2317: var LLVMBasicBlockRef ptrNeBr; 118:2318: var LLVMValueRef lhs = resetAndVisitExp(node.left); 118:2319: var LLVMValueRef rhs = resetAndVisitExp(node.right); -:2320: var LLVMValueRef len; -:2321: var LLVMValueRef resLenEq; -:2322: var LLVMValueRef resPtrEq; -:2323: var LLVMValueRef resMemEq; -:2324: -:2325: var LLVMBasicBlockRef endBr; -:2326: -:2327: // test .length and .ptr beforehand 118:2328: if isDyna do -:2329: { 106:2330: lenNeBr = instrBuilder.appendBasicBlock(currentFunction); 106:2331: lenEqBr = instrBuilder.appendBasicBlock(currentFunction); 106:2332: ptrEqBr = instrBuilder.appendBasicBlock(currentFunction); 106:2333: ptrNeBr = instrBuilder.appendBasicBlock(currentFunction); 106:2334: endBr = instrBuilder.appendBasicBlock(currentFunction); -:2335: 106:2336: var auto tsir = getTypeIr(tsl); 106:2337: const auto lt = getTypeIr(TypeUSize()); 106:2338: var auto len1 = instrBuilder.load(lt, instrBuilder.structGep(tsir, lhs, TSliceLayout.lenIdx)); 106:2339: var auto len2 = instrBuilder.load(lt, instrBuilder.structGep(tsir, rhs, TSliceLayout.lenIdx)); 106:2340: var auto cmp1 = instrBuilder.icmp(LLVMIntPredicate.EQ, len1, len2); 106:2341: instrBuilder.condBr(cmp1, lenEqBr, lenNeBr); -:2342: 106:2343: startBlock(lenNeBr); 106:2344: resLenEq = constBuilder.int(getTypeIr(TypeBool.instance()), node.operator == TokenType.notEqual, false); 106:2345: instrBuilder.br(endBr); -:2346: 106:2347: startBlock(lenEqBr); 106:2348: const auto ty = getPointerTypeIr(tsl.modified); 106:2349: lhs = instrBuilder.load(ty, instrBuilder.structGep(tsir, lhs, TSliceLayout.ptrIdx)); 106:2350: rhs = instrBuilder.load(ty, instrBuilder.structGep(tsir, rhs, TSliceLayout.ptrIdx)); 106:2351: var auto cmp2 = instrBuilder.icmp(LLVMIntPredicate.EQ, lhs, rhs); 106:2352: instrBuilder.condBr(cmp2, ptrEqBr, ptrNeBr); -:2353: 106:2354: startBlock(ptrEqBr); 106:2355: resPtrEq = constBuilder.int(getTypeIr(TypeBool.instance()), node.operator == TokenType.equal, false); 106:2356: instrBuilder.br(endBr); -:2357: 106:2358: startBlock(ptrNeBr); 106:2359: len = len1; -:2360: } -:2361: // bitwise cmp 118:2362: var auto sz = constBuilder.int(getTypeIr(TypeUSize()), bsz / 8, false); 224:2363: if isDyna do sz = instrBuilder.mul(len, sz); -:2364: 118:2365: exp = instrBuilder.call(libc_memcmp().tupleof, [lhs, rhs, sz]); 118:2366: exp = instrBuilder.icmp(LLVMIntPredicate.EQ, exp, zero32); 118:2367: instructionDi(node, exp); 118:2368: exp = instrBuilder.select(exp, one32, zero32); 118:2369: exp = instrBuilder.trunc(exp, getTypeIr(TypeBool.instance())); 118:2370: resMemEq = node.operator == TokenType.notEqual ? instrBuilder.not(exp) else exp; -:2371: 118:2372: if isDyna do -:2373: { 106:2374: instrBuilder.br(endBr); 106:2375: startBlock(endBr); 106:2376: exp = instrBuilder.phi(getTypeIr(TypeBool.instance())); 106:2377: instrBuilder.addIncoming(exp, [resLenEq, resPtrEq, resMemEq], [lenNeBr, ptrEqBr, ptrNeBr]); -:2378: } 12:2379: else do exp = resMemEq; -:2380: } -:2381: else do -:2382: { 6534:2383: resetAndVisitExp(node.right); 6534:2384: var auto rhs = loadExpIfLvalue(node.right); -:2385: -:2386: // optionally take cached value set to guarantee that an OptAssignExpression only eval once 6534:2387: exp = node.left.ir ? nodeIRtoValueRef(node.left) else resetAndVisitExp(node.left); 6534:2388: var auto lpt = exp; 6534:2389: var auto lhs = loadExpIfLvalue(node.left); -:2390: 6534:2391: const auto t0 = node.left.type.resolved(); 6534:2392: const auto t1 = node.right.type.resolved(); 6534:2393: const auto isFpOp = t0.isFloating(); 6534:2394: const auto isSign = t0.isSigned() || t1.isSigned(); -:2395: -:2396: var s32 cmpOpCode; 6534:2397: switch node.operator do -:2398: { 2729:2399: on equal do cmpOpCode = isFpOp ? LLVMRealPredicate.OEQ else LLVMIntPredicate.EQ; 2946:2400: on notEqual do cmpOpCode = isFpOp ? LLVMRealPredicate.ONE else LLVMIntPredicate.NE; 260:2401: on greater do cmpOpCode = isFpOp ? LLVMRealPredicate.OGT else isSign ? LLVMIntPredicate.SGT else LLVMIntPredicate.UGT; 117:2402: on greaterEqual do cmpOpCode = isFpOp ? LLVMRealPredicate.OGE else isSign ? LLVMIntPredicate.SGE else LLVMIntPredicate.UGE; 430:2403: on lesser do cmpOpCode = isFpOp ? LLVMRealPredicate.OLT else isSign ? LLVMIntPredicate.SLT else LLVMIntPredicate.ULT; 52:2404: on lesserEqual do cmpOpCode = isFpOp ? LLVMRealPredicate.OLE else isSign ? LLVMIntPredicate.SLE else LLVMIntPredicate.ULE; -:2405: else do assert(0); -:2406: } -:2407: -:2408: // store the lhs as it can be required for ConditionalExpression 6534:2409: var auto le = asLengthExp(node.left); 6534:2410: node.ir = (new CmpExpLeftIr).create(le ? le.expression.ir:LLVMValueRef else lpt, lhs):u8*; -:2411: 6534:2412: exp = isFpOp ? instrBuilder.fcmp(cmpOpCode:LLVMRealPredicate, lhs, rhs) 6501:2413: else instrBuilder.icmp(cmpOpCode:LLVMIntPredicate, lhs, rhs); -:2414: 6534:2415: instructionDi(node, exp); -:2416: } 6652:2417: } -:2418: -:2419: @override function visitConcatAssignExpression(ConcatAssignExpression* node) -:2420: { 800:2421: var auto tra = asTypeRcArray(node.type); 800:2422: var auto elt = tra.modified.resolved(); 800:2423: var auto result = resetAndVisitExp(node.left); 800:2424: var auto thisArg = instrBuilder.load(rcaType, exp); 800:2425: var auto ta = elt.asTypeAggregate() ? elt.asTypeTuple(); 800:2426: const auto padsz = ta?.align; 800:2427: var auto bsz = constBuilder.int(getTypeIr(TypeU32.instance()), elt.size + padsz, false); -:2428: 800:2429: exp = resetAndVisitExp(node.right); -:2430: -:2431: // initialized values are for the ConcatKind.lvalue case 800:2432: var auto ptr = exp; 800:2433: var auto len = onesize; -:2434: 800:2435: switch node.kind do -:2436: { -:2437: on ConcatKind.rvalue do -:2438: { 188:2439: ptr = nodeIRtoValueRef(node.asLvalue); 188:2440: instrBuilder.store(exp, ptr); 188:2441: continue on ConcatKind.lvalue; -:2442: } -:2443: on ConcatKind.slice do -:2444: { 559:2445: const auto tslir = getTypeIr(asTypeSlice(node.right.type)); 559:2446: ptr = instrBuilder.structGep(tslir, exp, TSliceLayout.ptrIdx); 559:2447: ptr = instrBuilder.load(getPointerTypeIr(elt), ptr); 559:2448: len = instrBuilder.structGep(tslir, exp, TSliceLayout.lenIdx); 559:2449: len = instrBuilder.load(getTypeIr(TypeUSize()), len); 559:2450: continue on; -:2451: } -:2452: on ConcatKind.lvalue do -:2453: { 800:2454: rcaIncrement(node.right, exp); 800:2455: var auto e = instrBuilder.call(rtl_rcaAppend().tupleof, [thisArg, ptr, len, bsz]); 800:2456: instrBuilder.store(e, result); 800:2457: instructionDi(node, e); -:2458: } -:2459: } 800:2460: exp = result; 800:2461: } -:2462: -:2463: @override function visitConcatExpression(ConcatExpression* node) -:2464: { 88:2465: var auto ts = asTypeSlice(node.type); -:2466: -:2467: // Initialize the result before doing a SetLengthExp 88:2468: var auto result = resetAndVisitExp(node.result); 88:2469: instrBuilder.store(constBuilder.zeroInit(getTypeIr(node.type)), result); -:2470: -:2471: // eval tail (possibly another ConcatExp), get value or ptr for memcpy of "this" ConcatExp 88:2472: resetAndVisitExp(node.right); 158:2473: if node.isRightMemCpy do visitConcreteExpression(node.rightPtr); 88:2474: var auto right = exp; 88:2475: var auto rightLen = resetAndVisitExp(node.rightLength); -:2476: -:2477: // eval left (possibly another ConcatExp), get value or ptr for memcpy of "this" ConcatExp 88:2478: resetAndVisitExp(node.left); 139:2479: if node.isLeftMemCpy do visitConcreteExpression(node.leftPtr); 88:2480: var auto left = exp; 88:2481: var auto leftLen = resetAndVisitExp(node.leftLength); -:2482: -:2483: // set "this" ConcatExp length as after L/R eval the L/R length is correct 88:2484: resetAndVisitExp(node.setLength); 88:2485: var auto dest = resetAndVisitExp(node.destPtr); -:2486: -:2487: // copy or append L 88:2488: if !node.isLeftMemCpy do -:2489: { 50:2490: if node.left.isLvalue() do left = instrBuilder.load(getTypeIr(node.left.type), left); 37:2491: instrBuilder.store(left, dest); -:2492: } -:2493: else do -:2494: { 51:2495: var auto len8 = instrBuilder.mul(leftLen, constBuilder.int(getTypeIr(TypeUSize()), ts.modified.resolved().size / 8, false)); 51:2496: instrBuilder.memmove(dest, 0, left, 0, len8); -:2497: } -:2498: // copy or append R 88:2499: dest = instrBuilder.gep(getTypeIr(asTypePointer(node.destPtr.type).modified), dest, [leftLen]); 88:2500: if !node.isRightMemCpy do -:2501: { 21:2502: if node.right.isLvalue() do right = instrBuilder.load(getTypeIr(node.right.type), right); 18:2503: instrBuilder.store(right, dest); -:2504: } -:2505: else do -:2506: { 70:2507: var auto len8 = instrBuilder.mul(rightLen, constBuilder.int(getTypeIr(TypeUSize()), ts.modified.resolved().size / 8, false)); 70:2508: instrBuilder.memmove(dest, 0, right, 0, len8); -:2509: } -:2510: 88:2511: exp = result; 88:2512: } -:2513: -:2514: @override function visitConditionalExpression(ConditionalExpression* node) -:2515: { 536:2516: resetAndVisitExp(node.condition); 536:2517: loadExpIfLvalue(node.condition); 536:2518: visitConcreteType(node.type); -:2519: 536:2520: if node.thenExpression.isLiteral() && node.elseExpression.isLiteral() do -:2521: { 18:2522: var auto cn = exp; 18:2523: var auto e1 = resetAndVisitExp(node.thenExpression); 18:2524: var auto e2 = resetAndVisitExp(node.elseExpression); 18:2525: exp = instrBuilder.select(cn, e1, e2); 18:2526: instructionDi(node, exp); 18:2527: return; -:2528: } -:2529: 518:2530: var auto thenStart = instrBuilder.appendBasicBlock(currentFunction); -:2531: var LLVMBasicBlockRef thenBlock; 518:2532: var auto elseStart = instrBuilder.appendBasicBlock(currentFunction); -:2533: var LLVMBasicBlockRef elseBlock; 518:2534: var auto phiBlock = instrBuilder.appendBasicBlock(currentFunction); 518:2535: const bool isLvalue = node.isLvalue(); -:2536: 518:2537: instrBuilder.condBr(exp, thenStart, elseStart); -:2538: 518:2539: startBlock(thenStart); 518:2540: if node.isShorthandSyntax do -:2541: { -:2542: // dont re-evaluate, the exp is stored in the ir field 28:2543: var auto cei = node.condition.ir:CmpExpLeftIr*; 28:2544: exp = isLvalue ? cei.asLvalue else cei.asRvalue; -:2545: } -:2546: else do -:2547: { 490:2548: resetAndVisitExp(node.thenExpression); 490:2549: if !isLvalue && node.thenExpression.isLvalue() do 197:2550: exp = instrBuilder.load(getTypeIr(node.thenExpression.type), exp); -:2551: } 518:2552: var auto thenExp = exp; 518:2553: thenBlock = currentBlock; 518:2554: instrBuilder.br(phiBlock); -:2555: 518:2556: startBlock(elseStart); 518:2557: var auto p = node.elseExpression.startPos; 518:2558: if doCover && p.line != node.startPos.line do 2:2559: cover(p); 518:2560: resetAndVisitExp(node.elseExpression); 518:2561: if !isLvalue && node.elseExpression.isLvalue() do 19:2562: exp = instrBuilder.load(getTypeIr(node.elseExpression.type), exp); 518:2563: var auto elseExp = exp; 518:2564: elseBlock = currentBlock; 518:2565: instrBuilder.br(phiBlock); -:2566: 518:2567: startBlock(phiBlock); 518:2568: if !isTypeVoid(node.type) do -:2569: { 510:2570: var auto t = getTypeIr(node.thenExpression.type); 510:2571: if node.isLvalue() do 66:2572: t = LLVMPointerType(t, 0); 510:2573: var auto phi = instrBuilder.phi(t); 510:2574: instrBuilder.addIncoming(phi, [thenExp, elseExp], [thenBlock, elseBlock]); 510:2575: exp = phi; 510:2576: instructionDi(node, phi); -:2577: } 8:2578: else do exp = null; 518:2579: } -:2580: -:2581: @override function visitContinueOnStatement(ContinueOnStatement* node) -:2582: { 19:2583: freeManagedLocals(node, node.managedLocals); 19:2584: if doCover do cover(node.startPos); 19:2585: exp = instrBuilder.br(nodeIRtoBlockRef(node)); 19:2586: instructionDi(node, exp); 19:2587: } -:2588: -:2589: @override function visitContinueStatement(ContinueStatement* node) -:2590: { 325:2591: if node.expression do resetAndVisitExp(node.expression); 205:2592: freeManagedLocals(node, node.managedLocals); 215:2593: if doCover do cover(node.startPos); 205:2594: if !node.$label do -:2595: { 203:2596: var auto lbr = node.target.ir:LoopBlockRefIr*; 203:2597: exp = instrBuilder.br(lbr.continueBr); -:2598: } -:2599: else do -:2600: { 2:2601: assert (node.symbol.astNode.ir); 2:2602: var auto bir = node.symbol.astNode.ir:LoopBlockRefIr*; 2:2603: exp = instrBuilder.br(bir.continueBr); -:2604: } 205:2605: instructionDi(node, exp); 205:2606: } -:2607: -:2608: @override function visitDeclExpression(DeclExpression* node) -:2609: { 960:2610: if var auto vd = symToVarDecl(node.declaration.symbol) do -:2611: { -:2612: // 1. init is done on BLockStatement entry due to the possible -:2613: // bypass, e.g in if the DeclExp is a AndAndExp RHS -:2614: // 2. BUG: DeclExp can be completly skipped due to the effect of -:2615: // `ast.expressions.getArrayOpResult()` 480:2616: exp = nodeIRtoValueRef(vd); -:2617: } 939:2618: if node.expression do visitConcreteExpression(node.expression); 480:2619: } -:2620: -:2621: @override function visitDeleteExpression(DeleteExpression* node) -:2622: { 131:2623: var auto v1 = resetAndVisitExp(node.expression); 131:2624: var auto v2 = loadExpIfLvalue(node.expression); 262:2625: if var FunctionDeclaration* fd = node.dtor do -:2626: { 71:2627: if !fd.ir do 6:2628: visitFunctionDeclaration(fd); 71:2629: var auto thisPtr = v2; 71:2630: var auto callee = nodeIRtoValueRef(fd); 71:2631: if fd.virtualIndex != -1 do -:2632: { 10:2633: var auto ta = asTypeAggregate(fd.parameters.ptr[0].type.asTypePointer().modified); 10:2634: var auto ad = ta.declaration; 10:2635: var auto vtty = ad.vtableVar.type; 10:2636: var auto ftpe = LLVMTypeOf(callee); 10:2637: var auto vidx = constBuilder.int(getTypeIr(TypeU32.instance()), fd.virtualIndex + 1, false); 10:2638: callee = instrBuilder.structGep(getTypeIr(ta), thisPtr, 0); 10:2639: callee = instrBuilder.load(getTypeIr(vtty), callee); 10:2640: callee = instrBuilder.gep(getTypeIr(asTypePointer(vtty).modified), callee, [zero32, vidx]); 10:2641: callee = instrBuilder.load(ftpe, callee); -:2642: } 71:2643: var auto e = instrBuilder.call(getTypeIr(fd.asTypeDeclared), callee, [thisPtr]); 71:2644: instructionDi(node, e); -:2645: } 131:2646: if node.deallocator do -:2647: { 2:2648: var auto fd = symToFuncDecl(node.deallocator.symbol); 2:2649: if !fd.ir do 1:2650: visitFunctionDeclaration(fd); 2:2651: var auto p = instrBuilder.bitCast(v2, getTypeIr(fd.parameters[0].type)); 2:2652: var auto e = instrBuilder.call(getTypeIr(fd.asTypeDeclared), nodeIRtoValueRef(fd), [p]); 2:2653: instructionDi(node, e); -:2654: } 129:2655: else do instrBuilder.free(v2); 131:2656: if node.expression.isLvalue() do 130:2657: instrBuilder.store(nullPtr, v1); 131:2658: } -:2659: -:2660: @override function visitDerefExpression(DerefExpression* node) -:2661: { 1326:2662: resetAndVisitExp(node.expression); 1326:2663: exp = loadExpIfLvalue(node.expression); 1326:2664: instructionDi(node, exp); 1326:2665: } -:2666: -:2667: @override function visitDivAssignExpression(const DivAssignExpression* node) -:2668: { 48:2669: visitBinaryAssignExpression(node); 48:2670: } -:2671: -:2672: @override function visitDivExpression(const DivExpression* node) -:2673: { 274:2674: visitBinaryExpression(node); 274:2675: } -:2676: -:2677: @override function visitDollarExpression(const DollarExpression* node) -:2678: { 104:2679: visitConcreteExpression(node.expression); 104:2680: } -:2681: -:2682: @override function visitDotExpression(DotExpression* node) -:2683: { -:2684: // `a.b` but `a` is a pointer. -:2685: // If this pointer is a lvalue then an additional load is required 10238:2686: const auto tp = asTypePointer(node.expression.type); 10238:2687: const auto tpa = tp ? asTypeAggregate(tp.modified) else null; 10238:2688: const auto loadAgain = tpa && node.expression.isLvalue(); -:2689: 10238:2690: var auto oae = asOptAccessExp(node.expression); 10238:2691: if oae do -:2692: { -:2693: // a? -> (a != null), so the implicitDeref cant be true 45:2694: assert(!loadAgain); -:2695: } 10238:2696: visitConcreteExpression(node.expression); 10238:2697: if loadAgain do -:2698: { 7255:2699: exp = instrBuilder.load(getPointerTypeIr(tpa), exp); 7255:2700: instructionDi(node, exp); -:2701: } 10238:2702: if node.checkDotVar do -:2703: { 7320:2704: nullStructGepSpecifier ?= instrBuilder.globalStringPtr(unitNode.scope.filename ~ ":%d:%d: runtime error, member read with null `this`\n\0"); 7320:2705: checkNull(node.dotted.startPos, exp, nullStructGepSpecifier); -:2706: } 10238:2707: visitConcreteExpression(node.dotted); 10283:2708: if oae do optAccessFinalize(oae); 10238:2709: } -:2710: 41:2711: @override function visitExpressionAlias(const ExpressionAlias* node) { } -:2712: -:2713: @override function visitExpressionStatement(ExpressionStatement* node) -:2714: { 10807:2715: exp = null; 10807:2716: visitConcreteExpression(node.expression); 11263:2717: if doCover do cover(node.startPos); 10807:2718: } -:2719: -:2720: @override function visitFloatExpression(FloatExpression* node) -:2721: { 54:2722: exp = constBuilder.real(getTypeIr(node.type), node.value); 54:2723: } -:2724: -:2725: @override function visitForeachStatement(ForeachStatement* node) -:2726: { 524:2727: if doCover do cover(node.startPos); 508:2728: var auto v = (new LLVMValueRef[+])(node.variables.length); 508:2729: foreach (const auto i; const auto vd) in node.variables do -:2730: { 817:2731: visitVariableDeclaration(vd); 817:2732: v.ptr[i] = nodeIRtoValueRef(vd); -:2733: } -:2734: 508:2735: var auto v0 = node.variables.ptr[0]; 508:2736: var auto testBr = instrBuilder.appendBasicBlock(currentFunction); 508:2737: var auto bodyBr = instrBuilder.appendBasicBlock(currentFunction); 508:2738: var auto incBr = instrBuilder.appendBasicBlock(currentFunction); 508:2739: var auto endBr = instrBuilder.appendBasicBlock(currentFunction); 508:2740: const auto isReversed = node.isReversed; 508:2741: const auto isIndexRValue = v0.isConst(); 508:2742: var auto incOrDec = isReversed ? &instrBuilder.sub else &instrBuilder.add; 508:2743: var auto pred = LLVMIntPredicate.EQ; 508:2744: var auto re = asRangeExp(node.expression); -:2745: 508:2746: node.ir = (new LoopBlockRefIr).create(incBr, endBr):u8*; -:2747: -:2748: var LLVMValueRef minIndex; -:2749: var LLVMValueRef maxIndex; -:2750: var LLVMValueRef index; -:2751: var LLVMTypeRef indexType; -:2752: var LLVMValueRef iterable; -:2753: var TypeStaticArray* tsa; -:2754: var TypeSlice* tsl; -:2755: var TypeRcArray* tra; -:2756: var TypeModified* tm; -:2757: var LLVMValueRef rcaThisArg; -:2758: var LLVMValueRef baseAddress; -:2759: var LLVMValueRef readIndex; -:2760: var LLVMValueRef nextIndex; -:2761: var LLVMValueRef firstIndex; -:2762: 508:2763: if re do -:2764: { 199:2765: indexType = getTypeIr(v0.type); 199:2766: resetAndVisitExp(re.left); 199:2767: minIndex = loadExpIfLvalue(re.left); 199:2768: resetAndVisitExp(re.right); 199:2769: maxIndex = loadExpIfLvalue(re.right); 199:2770: index = v.ptr[0]; -:2771: } -:2772: else do -:2773: { 309:2774: resetAndVisitExp(node.expression); 309:2775: iterable = exp; 309:2776: indexType = getTypeIr(v0.type); 309:2777: minIndex = constBuilder.int(indexType, 0, false); 309:2778: index = v.ptr[0]; 309:2779: var auto t = node.expression.type.resolved(); 309:2780: if (tm = tsa = t.asTypeStaticArray()) do -:2781: { 22:2782: maxIndex = constBuilder.int(indexType, tsa.length(), false); 22:2783: baseAddress = instrBuilder.gep(getTypeIr(tsa.modified), iterable, [zero32]); -:2784: } 287:2785: else do if (tm = tsl = t.asTypeSlice()) do -:2786: { 59:2787: const auto tslir = getTypeIr(tsl); 59:2788: maxIndex = instrBuilder.structGep(tslir, iterable, TSliceLayout.lenIdx); 59:2789: maxIndex = instrBuilder.load(getTypeIr(TypeUSize()), maxIndex); 59:2790: baseAddress = instrBuilder.structGep(tslir, iterable, TSliceLayout.ptrIdx); 59:2791: baseAddress = instrBuilder.load(getPointerTypeIr(tsl.modified), baseAddress); -:2792: } 228:2793: else do if (tm = tra = t.asTypeRcArray()) do -:2794: { 228:2795: rcaThisArg = instrBuilder.load(rcaType, iterable); 228:2796: maxIndex = instrBuilder.call(rtl_rcaGetLength().tupleof, [rcaThisArg]); 228:2797: instructionDi(node, maxIndex); 228:2798: baseAddress = instrBuilder.call(rtl_rcaPtr().tupleof, [rcaThisArg]); 228:2799: instructionDi(node, baseAddress); -:2800: } -:2801: else do assert(0); -:2802: } -:2803: 508:2804: if isReversed do -:2805: { 53:2806: var auto tmp = maxIndex; 53:2807: maxIndex = instrBuilder.sub(minIndex, onesize); 53:2808: minIndex = instrBuilder.sub(tmp, onesize); -:2809: } 508:2810: var auto firstIndexBr = currentBlock; 508:2811: if isIndexRValue do 505:2812: firstIndex = minIndex; -:2813: else do 3:2814: instrBuilder.store(instrBuilder.truncOrBitCast(minIndex, indexType), index); -:2815: 508:2816: instrBuilder.br(testBr); -:2817: -:2818: // test 508:2819: startBlock(testBr); 508:2820: if isIndexRValue do -:2821: { 505:2822: readIndex = instrBuilder.phi(indexType); 505:2823: v0.ir = readIndex:u8*; -:2824: } 3:2825: else do readIndex = instrBuilder.load(indexType, index); 508:2826: var auto condition = instrBuilder.icmp(pred, readIndex, maxIndex); 508:2827: var auto e = instrBuilder.condBr(condition, endBr, bodyBr); 508:2828: instructionDi(node, e); -:2829: // associate aggregate elem, visit body 508:2830: startBlock(bodyBr); 508:2831: if tsa || tsl || tra do -:2832: { 309:2833: const auto v1 = node.variables.ptr[1]; 309:2834: const auto ty = getTypeIr(v1.type); 309:2835: exp = instrBuilder.gep(getTypeIr(tm.modified), baseAddress, [readIndex]); 309:2836: v1.ir = (isImmediate in v1.flags ? instrBuilder.load(ty, exp) else exp):u8*; -:2837: } 508:2838: visitBlockStatement(node.blockStatement); -:2839: // implicit continue 508:2840: if node.blockStatement.flow.isContinueToNext() do 499:2841: instrBuilder.br(incBr); -:2842: // inc / next 508:2843: startBlock(incBr); 508:2844: nextIndex = incOrDec(instrBuilder, readIndex, constBuilder.int(indexType, 1, false)); 508:2845: if isIndexRValue do 505:2846: instrBuilder.addIncoming(readIndex, [firstIndex, nextIndex], [firstIndexBr, incBr]); 508:2847: if !isIndexRValue || diGenerate do 299:2848: instrBuilder.store(nextIndex, index); 508:2849: instrBuilder.br(testBr); 508:2850: startBlock(endBr); 508:2851: } -:2852: -:2853: @override function visitFunctionDeclaration(FunctionDeclaration* node) -:2854: { 128724:2855: if node.nextInstance do 27673:2856: visitConcreteDeclaration(node.nextInstance); 128724:2857: if node.isGeneric() || isInGeneric in node.scope.flags do 419:2858: return; 128305:2859: if tryLLVMIntrinsicDeclaration(node) do 27:2860: return; 128277:2861: if node.linkageKind == LinkageKind.foreign && node.name && matchImplicitLibcDecl(node) do 130:2862: return; 128147:2863: if pass == 0 do -:2864: { 35159:2865: visitConcreteType(node.returnType); 35159:2866: functions.append(node); 35159:2867: return; -:2868: } -:2869: 92988:2870: const DeclModuleInfo di = getDeclModuleInfo(node); 92988:2871: if di.isVisited do 68855:2872: return; -:2873: 24133:2874: var auto oldDiScope = diScope; 24133:2875: var auto oldCurrFunc = currentFunction; 24133:2876: var auto oldThisExp = thisExp; 24133:2877: var auto oldExp = exp; -:2878: 100899:2879: each:[function[V](V vd) => visitVariableDeclaration(vd)](node.parameters); -:2880: 24133:2881: const auto isVariadic = FunctionFlag.isCeeVariadic in node.flags; 24133:2882: const auto paramIrCnt = node.parameters.length:u32; -:2883: -:2884: // for anon funcs: they are not visited when pass is 0 -:2885: // but the type ir is usually set at this time 24133:2886: visitConcreteType(node.returnType); -:2887: 76766:2888: alias mapParamTypeIr = function[T](T t): auto => {visitVariableDeclaration(t); return t.isVar() ? getPointerTypeIr(t.type) else getTypeIr(t.type);}; 24133:2889: var auto paramT = map:[mapParamTypeIr](node.parameters); 24133:2890: var auto retT = node.isVar() ? getPointerTypeIr(node.returnType) else getTypeIr(node.returnType); -:2891: 24133:2892: var auto funcT = LLVMFunctionType(retT, paramT.ptr, paramIrCnt, isVariadic); 24133:2893: setTypeIr(node.asTypeDeclared, funcT , null); 24133:2894: assert(node.name, "should take the path of TypeFunction instead"); 24133:2895: const s8[+] linkageName = node.linkageName; 24133:2896: currentFunction = LLVMAddFunction(unitIr, (linkageName ~ "\0").ptr, funcT); 24133:2897: LLVMSetFunctionCallConv(currentFunction, LLVMCallConv.CCallConv); 24133:2898: if FunctionFlag.isInlineYes in node.flags do 41:2899: LLVMAddAttributeAtIndex(currentFunction, LLVMAttributeIndex.Function, getAttrInlineAlways()); 24092:2900: else do if FunctionFlag.isInlineMaybe in node.flags do 304:2901: LLVMAddAttributeAtIndex(currentFunction, LLVMAttributeIndex.Function, getAttrInlineMaybe()); -:2902: else do -:2903: { 23788:2904: LLVMAddAttributeAtIndex(currentFunction, LLVMAttributeIndex.Function, getAttrInlineNo()); 23788:2905: if node.getAtNoopt() do 1:2906: LLVMAddAttributeAtIndex(currentFunction, LLVMAttributeIndex.Function, getAttrOptNone()); -:2907: } 24133:2908: if node.getAtNoReturn() do 0:2909: LLVMAddAttributeAtIndex(currentFunction, LLVMAttributeIndex.Function, getAttrNoReturn()); 24133:2910: node.ir = currentFunction:u8*; -:2911: 24133:2912: var auto interruptedBB = currentBlock; -:2913: -:2914: // Because it's not known whether applications of generics declared in -I imports are already emitted, -:2915: // do it again and the linker will be instructed to drop any duplicates 24133:2916: const auto ad = node.symbol.parent.astNode:Declaration*; 24133:2917: const bool mustEmitGenApp = !node.irgened && 9958:2918: (ad && ad.isHeader && ad.genericParameters && ad.genericParameters.applied()) || 24131:2919: (node.isHeader && node.genericParameters && node.genericParameters.applied()); -:2920: 24133:2921: if !di.isImported || mustEmitGenApp do -:2922: { 4439:2923: node.irgened = true; 4439:2924: functionDeclarationDI(node); 4439:2925: visitFunctionBody(node); 4439:2926: if FunctionFlag.isAbstract in node.flags do 5:2927: generateAbstractBody(node); 4439:2928: if mustEmitGenApp do 3:2929: LLVMSetLinkage(currentFunction, LLVMLinkage.WeakAnyLinkage); -:2930: } -:2931: 24133:2932: currentFunction = oldCurrFunc; 24133:2933: thisExp = oldThisExp; 24133:2934: diScope = oldDiScope; 24133:2935: exp = oldExp; -:2936: -:2937: // ir gen of a body can happen in the midlle of another function, -:2938: // e.g if it's a forward decl used in a CallExp 24133:2939: currentBlock = null; 24133:2940: if interruptedBB do 3255:2941: startBlock(interruptedBB); 24133:2942: } -:2943: -:2944: @override function visitGotoStatement(GotoStatement* node) -:2945: { 6:2946: if doCover do cover(node.startPos); 6:2947: node.accept(this); 6:2948: node.symbol.astNode.ir ?= instrBuilder.appendBasicBlock(currentFunction):u8*; 6:2949: exp = instrBuilder.br(nodeIRtoBlockRef(node.symbol.astNode)); 6:2950: instructionDi(node, exp); 6:2951: } -:2952: -:2953: @override function visitIdentExpression(IdentExpression* node) -:2954: { 124482:2955: if var auto vd = symToVarDecl(node.symbol) do -:2956: { -:2957: // rvalue loop index 49326:2958: if isLoopCounter in vd.flags && vd.isConst() do 333:2959: return (exp = nodeIRtoValueRef(vd)):(); -:2960: -:2961: // used before declared. -:2962: // -:2963: // note: escapes can lead to generate ir for a local **before** declared, e.g -:2964: // `genericDecl; localDecl; nestedFunc_using_locaDecl; genericDcl:[nestedFunc_using_locaDecl]` -:2965: // all `genericDecl` applications are irgen'd first so the following conditions prevent the -:2966: // initializer to be put in the wrong body 48993:2967: if !node.ir && (!inNestedFunc || vd.escapeIndex == -1) do 48825:2968: visitVariableDeclaration(vd); -:2969: 48993:2970: if vd.isClassMember() || vd.isStructMember() do -:2971: { 11636:2972: if !exp do -:2973: { 3223:2974: assert(thisExp, "missing implicit `this` to perform a struct GEP"); 3223:2975: exp = thisExp; -:2976: } 11636:2977: assert (LLVMGetTypeKind(LLVMTypeOf(exp)) == LLVMTypeKind.PointerTypeKind); 11636:2978: const auto ta = asTypeAggregate(vd.symbol.parent.asType()).getTypeIr(); 11636:2979: exp = instrBuilder.structGep(ta, exp, vd.index); -:2980: } 37357:2981: else do if vd.isUnionMember() do -:2982: { -:2983: // bitcast to member type is done with a load() -:2984: } 37201:2985: else do if inNestedFunc && vd.escapeIndex != -1 do -:2986: { 91:2987: const auto ty = getPointerTypeIr(vd.type); 91:2988: const auto offs = constBuilder.int(getTypeIr(TypeU32.instance()), (vd.escapeIndex + 1) * (session.ptr_size / 8), false); -:2989: // escape struct contains only ptrs, offs advances per 8 bytes (vd.escapeIndex * 8), so use a gep elem_ty of size 1 91:2990: exp = instrBuilder.gep(getTypeIr(TypeU8.instance()), escapeFront(), [offs]); 91:2991: exp = instrBuilder.load(ty, exp); -:2992: } 37110:2993: else do if vd.isParameter do -:2994: { 3010:2995: exp = LLVMGetParam(currentFunction, vd.index); -:2996: } -:2997: else do -:2998: { 34100:2999: if isImmediate in vd.flags do 2672:3000: exp = vd.initializer ? vd.initializer.ir:LLVMValueRef else nodeIRtoValueRef(vd); -:3001: else do 31428:3002: exp = nodeIRtoValueRef(vd); -:3003: } -:3004: //instructionDi(node, exp); -:3005: } 25830:3006: else do if var auto fd = symToFuncDecl(node.symbol) do -:3007: { -:3008: // support for calls located before the callee declaration 12921:3009: if !fd.ir do visitFunctionDeclaration(fd); 10785:3010: exp = nodeIRtoValueRef(fd); -:3011: } 4260:3012: else do if var auto em = symToEnumMember(node.symbol) do -:3013: { 2104:3014: if !em.ir do -:3015: { 1251:3016: em.ir = resetAndVisitExp(em.value):u8*; -:3017: // member IR cache is only valid within a module, because -:3018: // even basic type aremapped to a specific LLVM context. -:3019: // so mark that IR for being reset 1251:3020: setVisited(em); -:3021: } 2104:3022: exp = nodeIRtoValueRef(em); -:3023: } -:3024: else do -:3025: { -:3026: // `with (Ident) do` ... : e.g scope changed to aggregate type -:3027: // `Ident.` ... : e.g access to static member -:3028: } 61908:3029: } -:3030: -:3031: @override function visitIfElseStatement(IfElseStatement* node) -:3032: { 4659:3033: var auto thenBr = instrBuilder.appendBasicBlock(currentFunction); 4659:3034: var auto elseBr = instrBuilder.appendBasicBlock(currentFunction); 4659:3035: var auto endBr = instrBuilder.appendBasicBlock(currentFunction); -:3036: var bool endReached; -:3037: 4893:3038: if doCover do cover(node.startPos); -:3039: 4659:3040: if node.ifVariable do 385:3041: visitVariableDeclaration(node.ifVariable); 4659:3042: resetAndVisitExp(node.condition); 4659:3043: loadExpIfLvalue(node.condition); 4659:3044: instrBuilder.condBr(exp, thenBr, elseBr); -:3045: 4659:3046: startBlock(thenBr); 4659:3047: var auto thenFlow = Flow.create(FlowKind.isNext); 4659:3048: if node.thenBlock do -:3049: { 4659:3050: visitBlockStatement(node.thenBlock); 4659:3051: thenFlow = node.thenBlock.flow; -:3052: } 4659:3053: if thenFlow.isContinueToNext() do -:3054: { 2704:3055: instrBuilder.br(endBr); 2704:3056: endReached = true; -:3057: } -:3058: 4659:3059: if !instrBuilder.getBasicBlockTerminator(currentBlock) do 4:3060: instrBuilder.br(endBr); -:3061: -:3062: var Flow elseFlow; 4659:3063: startBlock(elseBr); 4659:3064: if node.elseBlock do -:3065: { 683:3066: visitBlockStatement(node.elseBlock); 683:3067: elseFlow = node.elseBlock.flow; -:3068: } 3976:3069: else do elseFlow = Flow.create(FlowKind.isNext); 4659:3070: if elseFlow.isContinueToNext() do -:3071: { 4574:3072: instrBuilder.br(endBr); 4574:3073: endReached = true; -:3074: } -:3075: 4659:3076: if !instrBuilder.getBasicBlockTerminator(currentBlock) do 0:3077: instrBuilder.br(endBr); -:3078: 4659:3079: endReached ? startBlock(endBr) else instrBuilder.deleteBasicBlock(endBr); 4659:3080: } -:3081: -:3082: @override function visitImportDeclaration(const ImportDeclaration* node) -:3083: { -:3084: // contained Type are just used to get ident chains 144:3085: } -:3086: -:3087: @override function visitInExpression(InExpression* node) -:3088: { 169:3089: resetAndVisitExp(node.left); 169:3090: var auto lhs = loadExpIfLvalue(node.left); 169:3091: resetAndVisitExp(node.right); 169:3092: var auto rhs = loadExpIfLvalue(node.right); 169:3093: enumsetIsIncluded(lhs, rhs, asTypeEnumSet(node.right.type) != null); 169:3094: if node.negated do 39:3095: exp = instrBuilder.not(exp); 169:3096: } -:3097: -:3098: @override function visitIndexExpression(IndexExpression* node) -:3099: { 1314:3100: var auto old = exp; -:3101: 1314:3102: var auto indexExp = node.indexes[0]; 1314:3103: resetAndVisitExp(indexExp); 1314:3104: loadExpIfLvalue(indexExp); 1314:3105: var auto index = exp; -:3106: 1314:3107: exp = old; 1314:3108: visitConcreteExpression(node.expression); 2628:3109: if var auto tt = asTypeTuple(node.expression.type) do -:3110: { 104:3111: visitTypeTuple(tt); 104:3112: var auto i = getIntLiteral(indexExp).value; 104:3113: const auto t = getTypeIr(tt); 104:3114: exp = node.expression.isLvalue() ? instrBuilder.structGep(t, exp, i) else instrBuilder.extractValue(exp, i); 104:3115: return; -:3116: } 1210:3117: var auto array = loadExpIfLvalue(node.expression); -:3118: 1210:3119: if node.arrayType.kind == tkEnumSet do -:3120: { 60:3121: enumsetIsIncluded(array, index, asTypeEnumSet(indexExp.type) != null); 60:3122: return; -:3123: } -:3124: 1150:3125: index = instrBuilder.zextOrBitcast(index, getTypeIr(TypeUSize())); 1150:3126: if node.sourceLength && AdditionalCheck.bounds in session.additionalChecks do -:3127: { 627:3128: var auto upperBound = resetAndVisitExp(node.sourceLength); 627:3129: var auto failBr = instrBuilder.appendBasicBlock(currentFunction); 627:3130: var auto endBr = instrBuilder.appendBasicBlock(currentFunction); -:3131: 627:3132: upperBound = instrBuilder.zextOrBitcast(upperBound, getTypeIr(TypeUSize())); 627:3133: var auto c = instrBuilder.icmp(LLVMIntPredicate.UGE, index, upperBound); 627:3134: instrBuilder.condBr(c, failBr, endBr); -:3135: 627:3136: startBlock(failBr); 627:3137: boundsSpecifier ?= instrBuilder.globalStringPtr(unitNode.filename ~ ":%d:%d: runtime error, index `%d` >= array length `%d`\n\0"); 627:3138: var auto lineCol = getLineCol(node.expression.startPos); 627:3139: generateCheckFail([boundsSpecifier, lineCol[0], lineCol[1], index, upperBound]); -:3140: 627:3141: startBlock(endBr); -:3142: } 1150:3143: const auto tm = asTypeModified(node.expression.type); 1150:3144: exp = instrBuilder.gep(getTypeIr(tm.modified), array, [index]); 1150:3145: instructionDi(node, exp); 1150:3146: } -:3147: -:3148: @override function visitIntegerExpression(IntegerExpression* node) -:3149: { 58482:3150: visitConcreteType(node.type); 58482:3151: exp = constBuilder.int(getTypeIr(node.type), node.value, node.type.isSigned()); 58482:3152: } -:3153: -:3154: @override function visitLShiftAssignExpression(const LShiftAssignExpression* node) -:3155: { 2:3156: visitBinaryAssignExpression(node); 2:3157: } -:3158: -:3159: @override function visitLShiftExpression(const LShiftExpression* node) -:3160: { 8:3161: visitBinaryExpression(node); 8:3162: } -:3163: -:3164: @override function visitLabelDeclaration(LabelDeclaration* node) -:3165: { 10:3166: if !node.hasGoto do 4:3167: return; 6:3168: var auto lblBr = node.ir ? nodeIRtoBlockRef(node) else instrBuilder.appendBasicBlock(currentFunction); 6:3169: node.ir = lblBr:u8*; -:3170: -:3171: // risky, this relies on the fact that reachability analysis is 100% correct -:3172: // see https://gitlab.com/styx-lang/styx/-/issues/55 6:3173: if !instrBuilder.getBasicBlockTerminator(currentBlock) do 4:3174: instrBuilder.br(lblBr); -:3175: 6:3176: startBlock(lblBr); 6:3177: } -:3178: -:3179: @override function visitLambdaExpression(const LambdaExpression* node) -:3180: { -:3181: assert(0); -:3182: } -:3183: -:3184: @override function visitLengthExpression(LengthExpression* node) -:3185: { -:3186: // for `array ?= rhs` and to guarantee single eval, `array` as a lvalue is cached in `node.expression.ir` 2566:3187: exp = node.expression.ir ? nodeIRtoValueRef(node.expression) else resetAndVisitExp(node.expression); -:3188: // cache for CondExp 2566:3189: node.expression.ir = exp:u8*; 5132:3190: if const auto tsl = node.targetType.asTypeSlice() do -:3191: { 1003:3192: exp = instrBuilder.structGep(getTypeIr(tsl), exp, TSliceLayout.lenIdx); 1003:3193: instructionDi(node, exp); -:3194: // lengthExp is a rvalue, so that SetLengthExp is the only way to change VLA length 1003:3195: exp = instrBuilder.load(getTypeIr(TypeUSize()), exp); -:3196: } -:3197: else do -:3198: { 1563:3199: var auto thisArg = instrBuilder.load(rcaType, exp); 1563:3200: exp = instrBuilder.call(rtl_rcaGetLength().tupleof, [thisArg]); 1563:3201: instructionDi(node, exp); -:3202: } 2566:3203: } -:3204: -:3205: @override function visitModAssignExpression(const ModAssignExpression* node) -:3206: { 2:3207: visitBinaryAssignExpression(node); 2:3208: } -:3209: -:3210: @override function visitModExpression(const ModExpression* node) -:3211: { 59:3212: visitBinaryExpression(node); 59:3213: } -:3214: -:3215: @override function visitMulAssignExpression(const MulAssignExpression* node) -:3216: { 6:3217: visitBinaryAssignExpression(node); 6:3218: } -:3219: -:3220: @override function visitMulExpression(const MulExpression* node) -:3221: { 347:3222: visitBinaryExpression(node); 347:3223: } -:3224: -:3225: @override function visitNegExpression(NegExpression* node) -:3226: { 14:3227: const bool isFpOp = node.type.isFloating(); 14:3228: resetAndVisitExp(node.expression); 14:3229: loadExpIfLvalue(node.expression); 14:3230: exp = isFpOp ? instrBuilder.fneg(exp) else instrBuilder.neg(exp); 14:3231: instructionDi(node, exp); 14:3232: } -:3233: -:3234: @override function visitNewExpression(NewExpression* node) -:3235: { 686:3236: visitConcreteType(node.expression.type); 686:3237: var auto t = getTypeIr(node.expression.type); 686:3238: var auto i = getTypeInitIr(node.expression.type); 686:3239: if !node.allocator do -:3240: { 684:3241: exp = instrBuilder.malloc(t); -:3242: } -:3243: else do -:3244: { 2:3245: var auto fd = symToFuncDecl(node.allocator.symbol); 3:3246: if !fd.ir do visitFunctionDeclaration(fd); 2:3247: const u64 h = node.expression.type.resolved().size / 8; 2:3248: var auto num = constBuilder.int(getTypeIr(fd.parameters[0].type), h, false); 2:3249: exp = instrBuilder.call(getTypeIr(fd.asTypeDeclared), nodeIRtoValueRef(fd), [num]); 2:3250: instructionDi(node, exp); -:3251: } 686:3252: instrBuilder.store(i, exp); 686:3253: } -:3254: -:3255: @override function visitNotExpression(NotExpression* node) -:3256: { 507:3257: resetAndVisitExp(node.expression); 507:3258: loadExpIfLvalue(node.expression); 507:3259: exp = instrBuilder.not(exp); 507:3260: instructionDi(node, exp); 507:3261: } -:3262: -:3263: @override function visitNullExpression(NullExpression* node) -:3264: { 2753:3265: visitConcreteType(node.type); 2753:3266: exp = nullPtr; 2753:3267: } -:3268: -:3269: @override function visitOneCompExpression(OneCompExpression* node) -:3270: { 4:3271: resetAndVisitExp(node.expression); 4:3272: loadExpIfLvalue(node.expression); 4:3273: exp = instrBuilder.xor(exp, constBuilder.int(getTypeIr(node.expression.type), -1, true)); 4:3274: instructionDi(node, exp); 4:3275: } -:3276: -:3277: @override function visitOptAccessExpression(OptAccessExpression* node) -:3278: { 158:3279: visitConcreteType(node.valueType); 316:3280: if var auto v = node.valueVar do 45:3281: visitVariableDeclaration(v); -:3282: -:3283: var LLVMValueRef cond; -:3284: // `stuff?.a` -> `stuff.(@operator func(true)) ? stuff.a else node.valueVar` 316:3285: if var auto ce = asCallExp(node.expression) do -:3286: { 4:3287: visitConcreteExpression(ce.expression); 4:3288: var auto callee = exp; 4:3289: var auto fd = getFuncDeclForCall(ce); 4:3290: visitConcreteExpression(ce.arguments[0]); 4:3291: cond = instrBuilder.call(getTypeIr(fd.asTypeDeclared), callee, [exp]); 4:3292: instructionDi(node, cond); -:3293: } -:3294: // `stuff?.a` -> `stuff != null ? stuff.a else node.valueVar` -:3295: else do -:3296: { 154:3297: visitConcreteExpression(node.expression); 154:3298: cond = exp; 154:3299: var auto cir = node.expression.ir:CmpExpLeftIr*; 154:3300: assert(cir); 154:3301: exp = cir.asRvalue; -:3302: } -:3303: -:3304: // `stuff?.a` -> `stuff != null` which yields an rvalue 158:3305: assert(!node.expression.isLvalue()); -:3306: 158:3307: var auto skipBr = instrBuilder.appendBasicBlock(currentFunction); 158:3308: var auto contBr = instrBuilder.appendBasicBlock(currentFunction); 158:3309: var auto phiBr = instrBuilder.appendBasicBlock(currentFunction); -:3310: 158:3311: instrBuilder.condBr(cond, contBr, skipBr); -:3312: 158:3313: startBlock(skipBr); -:3314: 158:3315: var auto v1 = getTypeInitIr(node.valueType); -:3316: var LLVMValueRef lv; 316:3317: if var auto v = node.valueVar do -:3318: { 45:3319: lv = nodeIRtoValueRef(v); 45:3320: instrBuilder.store(v1, lv); -:3321: } 113:3322: else do lv = v1; 158:3323: instrBuilder.br(phiBr); 158:3324: const bool needPhi = !isTypeVoid(node.valueType); 158:3325: node.ir = (new OptExpIr).create(currentBlock, lv, phiBr, needPhi):u8*; -:3326: 158:3327: startBlock(contBr); 158:3328: } -:3329: -:3330: @override function visitOptAssignExpression(OptAssignExpression* node) -:3331: { 79:3332: var auto assgBr = instrBuilder.appendBasicBlock(currentFunction); 79:3333: var auto doneBr = instrBuilder.appendBasicBlock(currentFunction); 79:3334: var auto ptr = resetAndVisitExp(node.left); -:3335: // cache to prevent double eval, that cache must be handled in everything -:3336: // that toCondition can create, so far only special case is LengthExp 79:3337: var auto cmp = node.condition:CmpExpression*; 79:3338: var auto le = cmp ? cmp.left.asLengthExp() else null; 79:3339: var u8** cacheLoc = le ? &le.expression.ir else cmp ? &cmp.left.ir else &node.condition.ir; 79:3340: *cacheLoc = ptr:u8*; 79:3341: visitConcreteExpression(node.condition); 79:3342: loadExpIfLvalue(node.condition); -:3343: 79:3344: instrBuilder.condBr(exp, doneBr, assgBr); -:3345: 79:3346: startBlock(assgBr); 79:3347: var auto val = resetAndVisitExp(node.right); 79:3348: val = loadExpIfLvalue(node.right); 79:3349: instrBuilder.store(val, ptr); 79:3350: instrBuilder.br(doneBr); -:3351: 79:3352: startBlock(doneBr); 79:3353: exp = ptr; 79:3354: } -:3355: -:3356: @override function visitOrAssignExpression(const OrAssignExpression* node) -:3357: { 7:3358: visitBinaryAssignExpression(node); 7:3359: } -:3360: -:3361: @override function visitOrExpression(const OrExpression* node) -:3362: { 51:3363: visitBinaryExpression(node); 51:3364: } -:3365: -:3366: @override function visitOrOrExpression(OrOrExpression* node) -:3367: { 387:3368: var auto orOrBr = instrBuilder.appendBasicBlock(currentFunction); 387:3369: var auto orOrEndBr = instrBuilder.appendBasicBlock(currentFunction); -:3370: var LLVMBasicBlockRef actualOrOrBr; -:3371: 387:3372: resetAndVisitExp(node.left); 387:3373: loadExpIfLvalue(node.left); 387:3374: var auto actualStartBr = currentBlock; 387:3375: var auto v1 = exp; 387:3376: instrBuilder.condBr(v1, orOrEndBr, orOrBr); -:3377: 387:3378: startBlock(orOrBr); 387:3379: var auto p = node.right.startPos; 387:3380: if doCover && p.line != node.startPos.line do 1:3381: cover(p); 387:3382: resetAndVisitExp(node.right); 387:3383: loadExpIfLvalue(node.right); 387:3384: actualOrOrBr = currentBlock; 387:3385: var auto v2 = exp; 387:3386: instrBuilder.br(orOrEndBr); -:3387: 387:3388: startBlock(orOrEndBr); 387:3389: exp = instrBuilder.phi(getTypeIr(TypeBool.instance())); 387:3390: instrBuilder.addIncoming(exp, [v1, v2], [actualStartBr, actualOrOrBr]); 387:3391: instructionDi(node, exp); 387:3392: } -:3393: -:3394: @override function visitOverloadDeclaration(const OverloadDeclaration* node) -:3395: { -:3396: // dont codegen the expressions, the right one is already used by a CallExp 51:3397: } -:3398: -:3399: @override function visitPostDecExpression(PostDecExpression* node) -:3400: { 473:3401: visitConcreteType(node.type); 473:3402: visitConcreteExpression(node.expression); 473:3403: const auto isFloat = node.expression.type.isFloating(); 473:3404: const auto isPtr = asTypePointer(node.expression.type); 473:3405: const auto ty = getTypeIr(node.expression.type); 473:3406: var auto v1 = instrBuilder.load(ty, exp); -:3407: -:3408: var LLVMValueRef v2; 473:3409: const auto pp = node.operator == plusPlus; -:3410: 473:3411: if isPtr do 48:3412: v2 = instrBuilder.gep(getTypeIr(isPtr.modified), v1, [pp ? one32 else minusOne32]); -:3413: else do -:3414: { 425:3415: var auto inc = isFloat ? constBuilder.real(ty, 1.0) else constBuilder.int(ty, 1, false); 428:3416: if isFloat do v2 = pp ? instrBuilder.fadd(v1, inc) else instrBuilder.fsub(v1, inc); 422:3417: else do v2 = pp ? instrBuilder.add(v1, inc) else instrBuilder.sub(v1, inc); -:3418: } -:3419: 473:3420: instructionDi(node, v2); 473:3421: instrBuilder.store(v2, exp); 473:3422: exp = v1; 473:3423: } -:3424: -:3425: @override function visitPostIncExpression(const PostIncExpression* node) -:3426: { 404:3427: visitPostDecExpression(node); 404:3428: } -:3429: -:3430: @override function visitPreDecExpression(PreDecExpression* node) -:3431: { 240:3432: visitConcreteType(node.type); 240:3433: resetAndVisitExp(node.expression); 240:3434: const auto isFloat = node.expression.type.isFloating(); 240:3435: const auto isPtr = asTypePointer(node.expression.type); 240:3436: const auto ty = getTypeIr(node.expression.type); 240:3437: var auto v1 = instrBuilder.load(ty, exp); -:3438: -:3439: var LLVMValueRef v2; 240:3440: const bool pp = node.operator == eopPreInc; -:3441: 240:3442: if isPtr do 49:3443: v2 = instrBuilder.gep(getTypeIr(isPtr.modified), v1, [pp ? one32 else minusOne32]); -:3444: else do -:3445: { 191:3446: var auto inc = isFloat ? constBuilder.real(ty, 1.0) else constBuilder.int(ty, 1, false); 193:3447: if isFloat do v2 = pp ? instrBuilder.fadd(v1, inc) else instrBuilder.fsub(v1, inc); 189:3448: else do v2 = pp ? instrBuilder.add(v1, inc) else instrBuilder.sub(v1, inc); -:3449: } -:3450: 240:3451: instructionDi(node, v2); 240:3452: instrBuilder.store(v2, exp); 240:3453: } -:3454: -:3455: @override function visitPreIncExpression(const PreIncExpression* node) -:3456: { 140:3457: visitPreDecExpression(node); 140:3458: } -:3459: -:3460: @override function visitPtrExpression(PtrExpression* node) -:3461: { 2685:3462: visitConcreteType(node.type); 2685:3463: resetAndVisitExp(node.expression); 2685:3464: assert(node.expression.isLvalue()); -:3465: 2685:3466: var auto t = node.expression.type.resolved(); 2685:3467: switch t.kind do -:3468: { -:3469: on tkSta do -:3470: { 553:3471: exp = instrBuilder.gep(getTypeIr(t), exp, [zero32, zero32]); 553:3472: instructionDi(node, exp); -:3473: } -:3474: on tkSlice do -:3475: { 822:3476: exp = instrBuilder.structGep(getTypeIr(t), exp, TSliceLayout.ptrIdx); 822:3477: instructionDi(node, exp); 822:3478: exp = instrBuilder.load(getTypeIr(node.type), exp); -:3479: } -:3480: on tkRca do -:3481: { 1310:3482: var auto thisArg = instrBuilder.load(rcaType, exp); 1310:3483: exp = instrBuilder.call(rtl_rcaPtr().tupleof, [thisArg]); 1310:3484: instructionDi(node, exp); -:3485: } -:3486: else do assert(0); -:3487: } 2685:3488: } -:3489: -:3490: @override function visitRShiftAssignExpression(const RShiftAssignExpression* node) -:3491: { 2:3492: visitBinaryAssignExpression(node); 2:3493: } -:3494: -:3495: @override function visitRShiftExpression(const RShiftExpression* node) -:3496: { 9:3497: visitBinaryExpression(node); 9:3498: } -:3499: -:3500: @override function visitRangeExpression(RangeExpression* node) -:3501: { 84:3502: node.left.ir = resetAndVisitExp(node.left):u8*; 84:3503: node.right.ir = resetAndVisitExp(node.right):u8*; 84:3504: } -:3505: -:3506: @override function visitRcaAssignExpression(RcaAssignExpression* node) -:3507: { 237:3508: visitConcreteType(node.type); 237:3509: var auto tra = asTypeRcArray(node.type); -:3510: -:3511: // `exp` is not used but `node.ptr` and `node.length` -:3512: // requires it to be evaluated as `node.expression` -:3513: // can have its side effect in a special var that -:3514: // `node.ptr` and `node.length` will use 237:3515: resetAndVisitExp(node.expression); -:3516: 237:3517: var auto ptr = resetAndVisitExp(node.ptr); 237:3518: ptr = loadExpIfLvalue(node.ptr); -:3519: 237:3520: var auto len = resetAndVisitExp(node.length); 237:3521: len = loadExpIfLvalue(node.length); -:3522: 237:3523: var auto bsz = constBuilder.int(getTypeIr(TypeU32.instance()), tra.modified.resolved().size, false); 237:3524: var auto e = instrBuilder.call(rtl_rcaFromSlice().tupleof, [nullPtr, ptr, len, bsz]); 237:3525: exp = resetAndVisitExp(node.target); 237:3526: instrBuilder.store(e, exp); 237:3527: instructionDi(node, e); 237:3528: } -:3529: -:3530: @override function visitRefCountExpression(RefCountExpression* node) -:3531: { 130:3532: resetAndVisitExp(node.expression); 130:3533: var auto array = exp; 130:3534: var auto thisArg = instrBuilder.load(rcaType, exp); 130:3535: switch node.subOp do -:3536: { -:3537: on RefCountOp.refcount_ do -:3538: { 46:3539: exp = instrBuilder.call(rtl_rcaRefCount().tupleof, [thisArg]); 46:3540: instructionDi(node, exp); -:3541: } -:3542: on RefCountOp.incref_ do -:3543: { 1:3544: exp = instrBuilder.call(rtl_rcaIncRefCount().tupleof, [thisArg]); 1:3545: instructionDi(node, exp); -:3546: } -:3547: on RefCountOp.decref_ do -:3548: { 79:3549: var auto tra = asTypeRcArray(node.expression.type); 79:3550: if tra.nestedRcArrayDims do -:3551: { 5:3552: var auto d = constBuilder.int(getTypeIr(TypeU8.instance()), tra.nestedRcArrayDims, false); 5:3553: exp = instrBuilder.call(rtl_rcaDecRefCountNest().tupleof, [thisArg, d]); -:3554: } 74:3555: else do exp = instrBuilder.call(rtl_rcaDecRefCount().tupleof, getRcaDecrementArgs(tra, thisArg)); 79:3556: instructionDi(node, exp); 79:3557: instrBuilder.store(exp, array); -:3558: } -:3559: on RefCountOp.dup_ do -:3560: { 4:3561: var auto tra = asTypeRcArray(node.type); 4:3562: var auto bsz = constBuilder.int(getTypeIr(TypeU32.instance()), tra.modified.resolved().size, false); 4:3563: exp = instrBuilder.call(rtl_rcaDup().tupleof, [thisArg, bsz]); 4:3564: instructionDi(node, exp); -:3565: } -:3566: } 130:3567: } -:3568: -:3569: @override function visitReturnStatement(ReturnStatement* node) -:3570: { 5635:3571: if doCover do cover(node.startPos); 5468:3572: if node.expression do -:3573: { 6218:3574: if var auto e = resetAndVisitExp(node.expression) do -:3575: { 3103:3576: if !node.skipRcaProtection do 3083:3577: rcaIncrement(node.expression, e); 3103:3578: instructionDi(node.expression, e); -:3579: } -:3580: } 5468:3581: freeManagedLocals(node, node.managedLocals); 5617:3582: if currentEscapes do escapePop(); 5468:3583: if node.expression && !isTypeVoid(node.expression.type) do -:3584: { -:3585: // dec ref count but without freeing so that -:3586: // `a = call()` works just like `a = b` 2921:3587: rcaBeforeReturn(node.expression, exp); -:3588: 2921:3589: if !node.isVar do 2907:3590: exp = loadExpIfLvalue(node.expression); 2921:3591: exp = instrBuilder.ret(exp); -:3592: } 2547:3593: else do exp = instrBuilder.retVoid(); 5468:3594: instructionDi(node, exp); 5468:3595: } -:3596: -:3597: @override function visitSetLengthExpression(SetLengthExpression* node) -:3598: { -:3599: // get the array, it is represented as a struct, so a lvalue 296:3600: var auto array = resetAndVisitExp(node.expression); -:3601: 296:3602: resetAndVisitExp(node.newLength); 296:3603: var auto newLen = loadExpIfLvalue(node.newLength); -:3604: var LLVMValueRef newPtr; -:3605: var LLVMValueRef oldLen; -:3606: var TypeModified* arrayType; -:3607: 296:3608: var auto elt = node.expression.type.asTypeModified().modified; 296:3609: var auto ta = elt.asTypeAggregate(); 296:3610: var auto padt = ta ? elt.asTypeTuple(); 296:3611: const auto padsz = padt?.align; -:3612: -:3613: // explicit .length mutation of TypeSlice is not allowed -:3614: // but still used by TidExp 592:3615: if var auto tsl = node.expression.type.asTypeSlice() do -:3616: { 88:3617: var auto tslir = getTypeIr(tsl); -:3618: // GEPs to update the payload 88:3619: var auto lenRW = instrBuilder.structGep(tslir, array, TSliceLayout.lenIdx); 88:3620: var auto ptrRW = instrBuilder.structGep(tslir, array, TSliceLayout.ptrIdx); 88:3621: var auto ptrTY = getPointerTypeIr(tsl.modified); 88:3622: oldLen = instrBuilder.load(getTypeIr(TypeUSize()), lenRW); -:3623: // new length * elem size 88:3624: arrayType = tsl; 88:3625: var auto newSize= constBuilder.int(getTypeIr(TypeUSize()), (tsl.modified.resolved().size + padsz) / 8, false); 88:3626: newSize = instrBuilder.mul(newLen, newSize); -:3627: // the internal representation has the right ptr type, but realloc takes u8* 88:3628: var auto bitPtr = instrBuilder.load(ptrTY, ptrRW); 88:3629: var auto rightT = LLVMTypeOf(bitPtr); -:3630: // realloc() 88:3631: newPtr = instrBuilder.call(libc_realloc().tupleof, [bitPtr, newSize]); 88:3632: instructionDi(node, newPtr); 88:3633: newPtr = instrBuilder.bitCast(newPtr, rightT); -:3634: // update payload 88:3635: instrBuilder.store(newLen, lenRW); 88:3636: instrBuilder.store(newPtr, ptrRW); -:3637: } -:3638: else do -:3639: { 208:3640: var auto tra = node.expression.type.asTypeRcArray(); 208:3641: arrayType = tra; 208:3642: var auto thisArg= instrBuilder.load(rcaType, array); 208:3643: oldLen = instrBuilder.call(rtl_rcaGetLength().tupleof, [thisArg]); 208:3644: instructionDi(node, oldLen); 208:3645: var LLVMValueRef bitsArg= constBuilder.int(getTypeIr(TypeU32.instance()), tra.modified.resolved().size + padsz, false); -:3646: 416:3647: if var FunctionDeclaration* defDtor = ta ? ta.declaration.defaultDtor else null do -:3648: { 7:3649: if !defDtor.ir do visitFunctionDeclaration(defDtor); 7:3650: var auto e = instrBuilder.call(rtl_rcaElemDtor().tupleof, [thisArg, newLen, oldLen, bitsArg, nodeIRtoValueRef(defDtor)]); 7:3651: instructionDi(node, e); -:3652: } -:3653: 208:3654: thisArg = instrBuilder.call(rtl_rcaSetLength().tupleof, [thisArg, newLen, bitsArg]); 208:3655: instructionDi(node, thisArg); 208:3656: instrBuilder.store(thisArg, array); 208:3657: newPtr = instrBuilder.call(rtl_rcaPtr().tupleof, [thisArg]); 208:3658: instructionDi(node, newPtr); -:3659: } -:3660: // emplace initializers 296:3661: if node.isInitStored do -:3662: { 208:3663: var auto testBr = instrBuilder.appendBasicBlock(currentFunction); 208:3664: var auto putBr = instrBuilder.appendBasicBlock(currentFunction); 208:3665: var auto endBr = instrBuilder.appendBasicBlock(currentFunction); 208:3666: var auto toStore = getTypeInitIr(arrayType.modified.resolved()); -:3667: var LLVMValueRef indexN; 208:3668: var LLVMBasicBlockRef block0 = currentBlock; 208:3669: instrBuilder.br(testBr); -:3670: 208:3671: startBlock(testBr); 208:3672: var auto index = instrBuilder.phi(getTypeIr(TypeUSize())); 208:3673: var auto cmp = instrBuilder.icmp(LLVMIntPredicate.ULT, index, newLen); 208:3674: instrBuilder.condBr(cmp, putBr, endBr); -:3675: 208:3676: startBlock(putBr); 208:3677: var auto addr = instrBuilder.gep(getTypeIr(elt), newPtr, [index]); 208:3678: instrBuilder.store(toStore, addr); -:3679: 416:3680: if var auto defCtor = ta ? ta.declaration.defaultCtor else null do -:3681: { 7:3682: if !defCtor.ir do visitFunctionDeclaration(defCtor); 5:3683: var auto e = instrBuilder.call(getTypeIr(defCtor.asTypeDeclared), nodeIRtoValueRef(defCtor), [addr]); 5:3684: instructionDi(node, e); -:3685: } -:3686: 208:3687: indexN = instrBuilder.add(index, onesize); 208:3688: instrBuilder.addIncoming(index, [oldLen, indexN], [block0, putBr]); 208:3689: instrBuilder.br(testBr); -:3690: 208:3691: startBlock(endBr); -:3692: } 296:3693: exp = newLen; 296:3694: } -:3695: -:3696: @override function visitSliceExpression(SliceExpression* node) -:3697: { -:3698: var LLVMValueRef e2; -:3699: var LLVMValueRef e2ptr; 2002:3700: if node.assignRhs do -:3701: { 31:3702: e2 = e2ptr = resetAndVisitExp(node.assignRhs); 31:3703: if node.isElemAssign do 6:3704: e2 = loadExpIfLvalue(node.assignRhs); -:3705: } 2002:3706: var auto tsl = asTypeSlice(node.type); -:3707: 2002:3708: if node.isStatic do -:3709: { -:3710: var LLVMTypeRef t; 394:3711: if node.staticPtrProvider do -:3712: { 6:3713: visitVariableDeclaration(node.staticPtrProvider); 6:3714: t = getTypeIr(node.staticPtrProvider.type); 6:3715: exp = nodeIRtoValueRef(node.staticPtrProvider); -:3716: } -:3717: else do -:3718: { 388:3719: resetAndVisitExp(node.expression); 388:3720: visitConcreteType(node.type); 388:3721: t = getTypeIr(tsl.modified); 388:3722: exp = constBuilder.gep(t, exp, [zero32]); -:3723: } 394:3724: const u64 v1 = getIntLiteral(node.range.left).value; 394:3725: const u64 v2 = getIntLiteral(node.range.right).value - v1; 394:3726: var auto o = constBuilder.int(getTypeIr(TypeUSize()), v1, false); 394:3727: var auto n = constBuilder.int(getTypeIr(TypeUSize()), v2, false); 394:3728: exp = node.expression.asArrayExp() ? constBuilder.gep(t, exp, [zero32, o]) else constBuilder.gep(t, exp, [o]); 394:3729: exp = constBuilder.structInContext(ctxt, [n, exp]); 394:3730: return; -:3731: } -:3732: 1608:3733: resetAndVisitExp(node.expression); -:3734: var LLVMValueRef array; 1608:3735: if node.sourcePtr do -:3736: { 646:3737: array = resetAndVisitExp(node.sourcePtr); 646:3738: array = loadExpIfLvalue(node.sourcePtr); -:3739: } -:3740: else do -:3741: { 962:3742: array = exp; 962:3743: array = loadExpIfLvalue(node.expression); -:3744: } -:3745: 1608:3746: var auto lower = resetAndVisitExp(node.range.left); 1608:3747: lower = loadExpIfLvalue(node.range.left); 1608:3748: var auto upper = resetAndVisitExp(node.range.right); 1608:3749: upper = loadExpIfLvalue(node.range.right); 1608:3750: var auto length = instrBuilder.sub(upper, lower); 1608:3751: var auto len8 = instrBuilder.mul(length, constBuilder.int(getTypeIr(TypeUSize()), tsl.modified.resolved().size / 8, false)); 1608:3752: var auto source = instrBuilder.gep(getTypeIr(tsl.modified), array, [lower]); -:3753: -:3754: // cache for bounds check of slice[] = otherSlice[] 1608:3755: node.range.left.ir = length:u8*; 1608:3756: node.range.right.ir = len8:u8*; -:3757: 1608:3758: visitConcreteExpression(node.result); 1608:3759: var auto dyna = exp; 1608:3760: var auto tsir = getTypeIr(node.result.type); -:3761: 1608:3762: var auto lenW = instrBuilder.structGep(tsir, dyna, TSliceLayout.lenIdx); 1608:3763: var auto ptrW = instrBuilder.structGep(tsir, dyna, TSliceLayout.ptrIdx); -:3764: 1608:3765: if AdditionalCheck.bounds in session.additionalChecks && node.sourceLength do -:3766: { 169:3767: var auto upperBound = resetAndVisitExp(node.sourceLength); 169:3768: var auto pass1Br = instrBuilder.appendBasicBlock(currentFunction); 169:3769: var auto fail1Br = instrBuilder.appendBasicBlock(currentFunction); 169:3770: var auto pass2Br = instrBuilder.appendBasicBlock(currentFunction); 169:3771: var auto fail2Br = instrBuilder.appendBasicBlock(currentFunction); 169:3772: var auto fail3Br = instrBuilder.appendBasicBlock(currentFunction); 169:3773: var auto endBr = instrBuilder.appendBasicBlock(currentFunction); -:3774: 169:3775: upperBound = instrBuilder.zextOrBitcast(upperBound, getTypeIr(TypeUSize())); 169:3776: lower = instrBuilder.zextOrBitcast(lower, getTypeIr(TypeUSize())); 169:3777: upper = instrBuilder.zextOrBitcast(upper, getTypeIr(TypeUSize())); -:3778: 169:3779: var auto c = instrBuilder.icmp(LLVMIntPredicate.UGT, lower, upperBound); 169:3780: instrBuilder.condBr(c, fail1Br, pass1Br); -:3781: 169:3782: startBlock(fail1Br); 169:3783: boundsSpecifier ?= instrBuilder.globalStringPtr(unitNode.scope.filename ~ ":%d:%d: runtime error, index `%d` >= array length `%d`\n\0"); 169:3784: var auto lineCol = getLineCol(node.expression.startPos); 169:3785: generateCheckFail([boundsSpecifier, lineCol[0], lineCol[1], lower, upperBound]); -:3786: 169:3787: startBlock(pass1Br); 169:3788: c = instrBuilder.icmp(LLVMIntPredicate.UGT, upper, upperBound); 169:3789: instrBuilder.condBr(c, fail2Br, pass2Br); -:3790: 169:3791: startBlock(fail2Br); 169:3792: generateCheckFail([boundsSpecifier, lineCol[0], lineCol[1], upper, upperBound]); -:3793: 169:3794: startBlock(pass2Br); 169:3795: c = instrBuilder.icmp(LLVMIntPredicate.UGT, lower, upper); 169:3796: instrBuilder.condBr(c, fail3Br, endBr); -:3797: 169:3798: startBlock(fail3Br); 169:3799: sliceHiLowSpecifier ?= instrBuilder.globalStringPtr(unitNode.scope.filename ~ ":%d:%d: runtime error, lower slice index `%d` > upper `%d`\n\0"); 169:3800: generateCheckFail([sliceHiLowSpecifier, lineCol[0], lineCol[1], lower, upper]); -:3801: 169:3802: startBlock(endBr); -:3803: } -:3804: 1608:3805: instrBuilder.store(source, ptrW); 1608:3806: instrBuilder.store(length, lenW); -:3807: 1608:3808: if e2 do -:3809: { 31:3810: if node.isElemAssign do -:3811: { 6:3812: ptrW = instrBuilder.load(getPointerTypeIr(tsl.modified), ptrW); 6:3813: if node.assignRhs.type.resolved().size == 8 do -:3814: { 1:3815: e2 = instrBuilder.bitCast(e2, getTypeIr(TypeU8.instance())); 1:3816: instrBuilder.memset(ptrW, e2, len8, 0); -:3817: } -:3818: else do -:3819: { 5:3820: var auto testBr = instrBuilder.appendBasicBlock(currentFunction); 5:3821: var auto bodyBr = instrBuilder.appendBasicBlock(currentFunction); 5:3822: var auto doneBr = instrBuilder.appendBasicBlock(currentFunction); 5:3823: var auto index0 = zerosize; 5:3824: var auto block0 = currentBlock; -:3825: var LLVMValueRef indexN; 5:3826: instrBuilder.br(testBr); -:3827: 5:3828: startBlock(testBr); 5:3829: var auto counterVal = instrBuilder.phi(getTypeIr(TypeUSize())); 5:3830: var auto cmp = instrBuilder.icmp(LLVMIntPredicate.EQ, counterVal, length); 5:3831: instrBuilder.condBr(cmp, doneBr, bodyBr); -:3832: 5:3833: startBlock(bodyBr); 5:3834: instrBuilder.store(e2, instrBuilder.gep(getTypeIr(tsl.modified), ptrW, [counterVal])); 5:3835: indexN = instrBuilder.add(onesize, counterVal); 5:3836: instrBuilder.addIncoming(counterVal, [index0, indexN], [block0, bodyBr]); 5:3837: instrBuilder.br(testBr); -:3838: 5:3839: startBlock(doneBr); -:3840: } -:3841: } -:3842: else do -:3843: { -:3844: var LLVMValueRef rightLength; -:3845: var LLVMValueRef rightLength8; -:3846: // length cached from SliceExp 50:3847: if var auto sle = asSliceExp(node.assignRhs) do -:3848: { 22:3849: rightLength = nodeIRtoValueRef(sle.range.left); 22:3850: rightLength8 = nodeIRtoValueRef(sle.range.right); -:3851: } -:3852: // slice assigned to a variable -:3853: else do -:3854: { 3:3855: rightLength = instrBuilder.structGep(tsir, e2ptr, TSliceLayout.lenIdx); 3:3856: rightLength = instrBuilder.load(getTypeIr(TypeUSize()), rightLength); 3:3857: rightLength8= instrBuilder.mul(rightLength, constBuilder.int(getTypeIr(TypeUSize()), tsl.modified.resolved().size / 8, false)); -:3858: } -:3859: 25:3860: if AdditionalCheck.bounds in session.additionalChecks do -:3861: { 25:3862: var auto failBr = instrBuilder.appendBasicBlock(currentFunction); 25:3863: var auto passBr = instrBuilder.appendBasicBlock(currentFunction); -:3864: 25:3865: var auto cmp = instrBuilder.icmp(LLVMIntPredicate.NE, rightLength8, len8); 25:3866: instrBuilder.condBr(cmp, failBr, passBr); 25:3867: startBlock(failBr); 25:3868: sliceAssSpecifier ?= instrBuilder.globalStringPtr(unitNode.scope.filename ~ ":%d:%d: runtime error, source length `%d` and target length `%d` mismatch\n\0"); 25:3869: var auto lineCol = getLineCol(node.expression.startPos); 25:3870: generateCheckFail([sliceAssSpecifier, lineCol[0], lineCol[1], rightLength, length]); 25:3871: startBlock(passBr); -:3872: } 25:3873: const auto t = getPointerTypeIr(TypeU8.instance()); 25:3874: e2 = instrBuilder.load(t, instrBuilder.structGep(tsir, e2, TSliceLayout.ptrIdx)); 25:3875: instrBuilder.memmove(instrBuilder.load(t,ptrW), 0, e2, 0, rightLength8); -:3876: } -:3877: } -:3878: 1608:3879: exp = dyna; 1608:3880: } -:3881: -:3882: @override function visitStatement(Statement* node) -:3883: { 33912:3884: super(node); 33912:3885: if node.containsNoReturn do 0:3886: instrBuilder.unreachable(); 33912:3887: } -:3888: 44:3889: @override function visitStaticAssertDeclaration(const StaticAssertDeclaration* node) {} -:3890: -:3891: @override function visitStringExpression(StringExpression* node) -:3892: { 3239:3893: const s8[] value = node.value.text() ~ "\0"; -:3894: // check if the string contains inner null chars b/c LLVM guesses -:3895: // the size with strlen too and that can truncate the actual content 3239:3896: if strlen(value.ptr) == value.length - 1 && currentFunction do -:3897: { 1698:3898: exp = instrBuilder.globalStringPtr(value); -:3899: } -:3900: else do -:3901: { 1541:3902: var auto a = instrBuilder.string(value); 1541:3903: var auto g = LLVMAddGlobal(unitIr, LLVMTypeOf(a), (moduleString ~ ".string\0").ptr); 1541:3904: LLVMSetInitializer(g, a); 1541:3905: exp = constBuilder.gep(LLVMTypeOf(a), g, [zero32, zero32]); -:3906: } 3239:3907: } -:3908: -:3909: @override function visitStructDeclaration(StructDeclaration* node) -:3910: { 586:3911: if node.nextInstance do 89:3912: visitConcreteDeclaration(node.nextInstance); 586:3913: if node.isGeneric() do 50:3914: return; 536:3915: const DeclModuleInfo di = getDeclModuleInfo(node); 536:3916: if di.isVisited do -:3917: { -:3918: //printf("skip visit of aggregate %s in unit %s\n", node.name.text().ptr, unitNode.scope.filename.ptr); 47:3919: return; -:3920: } -:3921: //printf("visiting aggregate %s in unit %s\n", node.name.text().ptr, unitNode.scope.filename.ptr); -:3922: 489:3923: if node.symbol.recurseGuard do 0:3924: return; 489:3925: node.symbol.recurseGuard++; -:3926: 489:3927: var s8[+] linkageName = node.linkageName; 489:3928: var auto oldAggregateType = currentAggregateType; 489:3929: currentAggregateType = LLVMStructCreateNamed(ctxt, (linkageName ~ "\0").ptr); -:3930: //var Type* ts = node.symbol.asType(); -:3931: -:3932: // so that rtl.sx can use ref counted arrays without using its local `struct RcArray` -:3933: // which would create type mismatches 489:3934: if isRtlRootUnit && node.name.iptr() == rcArrayToken().iptr() do 44:3935: currentAggregateType = rcaTypePointee; -:3936: 489:3937: node.ir = currentAggregateType:u8*; -:3938: // Set a partial type IR, e.g if the body contains variable that are pointers/array of this type 489:3939: setTypeIr(node.symbol.asType(), currentAggregateType, constBuilder.zeroInit(currentAggregateType)); -:3940: // If the matching TypeClass is never visited explictly, mark it for reset here 489:3941: setVisited(node.symbol.asType()); -:3942: -:3943: var LLVMTypeRef[+] membersT; -:3944: var usize mtc; 489:3945: const auto oldPass = pass; 489:3946: pass = 0; 974:3947: if node.body do visitDeclarations(node.body); 489:3948: pass = oldPass; -:3949: 978:3950: if const auto len = node.symbol.children.length do -:3951: { 468:3952: membersT.length = len; 468:3953: foreach var auto c in node.symbol.children do -:3954: { 4646:3955: var auto vd = symToVarDecl(c); 4646:3956: if !vd || vd.isStatic() do 3689:3957: continue; 957:3958: membersT.ptr[mtc++] = getTypeIr(vd.type); -:3959: } 468:3960: membersT.length = mtc; -:3961: } -:3962: 489:3963: LLVMStructSetBody(currentAggregateType, membersT.ptr, membersT.length:u32, false); -:3964: 489:3965: if node.body do -:3966: { -:3967: var usize mc; -:3968: var LLVMValueRef[+] members; 970:3969: if const auto len = node.symbol.children.length do -:3970: { 468:3971: members.length = len; 468:3972: foreach var auto c in node.symbol.children do -:3973: { 4646:3974: var auto vd = symToVarDecl(c); 4646:3975: if !vd || vd.isStatic() do 3689:3976: continue; 957:3977: members.ptr[mc++] = getInitializer(vd); -:3978: } 468:3979: members.length = mc; -:3980: } -:3981: // Store the real initializer. 485:3982: var auto def = constBuilder.namedStruct(currentAggregateType, members); 485:3983: var auto t = node.symbol.asType(); 485:3984: setTypeIr(t, currentAggregateType, def); -:3985: 485:3986: if diGenerate do -:3987: { 265:3988: var LLVMMetadataRef[+] diMembers = getMemberDi(node.symbol); 265:3989: t.dbgIr = diBuilder.createStructType(diUnitRef, linkageName, -:3990: node.startPos.line, t.size, t.align, LLVMDIFlags.Zero, diMembers):u8*; -:3991: } -:3992: } -:3993: 489:3994: node.symbol.recurseGuard--; 489:3995: currentAggregateType = oldAggregateType; 489:3996: } -:3997: -:3998: @override function visitSubAssignExpression(const SubAssignExpression* node) -:3999: { 128:4000: visitBinaryAssignExpression(node); 128:4001: } -:4002: -:4003: @override function visitSubExpression(const SubExpression* node) -:4004: { 513:4005: visitBinaryExpression(node); 513:4006: } -:4007: 102:4008: @override function visitSuperExpression(const SuperExpression* node){ } -:4009: -:4010: @override function visitSwitchStatement(SwitchStatement* node) -:4011: { 272:4012: if doCover do cover(node.startPos); 256:4013: resetAndVisitExp(node.expression); 256:4014: loadExpIfLvalue(node.expression); 256:4015: var auto trapExp = exp; -:4016: -:4017: var LLVMBasicBlockRef endBr; 256:4018: var LLVMBasicBlockRef elseBr = instrBuilder.appendBasicBlock(currentFunction); 256:4019: var LLVMValueRef oldSwitch = currentSwitch; 256:4020: currentSwitch = instrBuilder.$switch(exp, elseBr, node.onMatchStatements.length:u32); -:4021: -:4022: // cases 256:4023: var auto caseBr = (new LLVMBasicBlockRef[+])(node.onMatchStatements.length); 256:4024: foreach (const auto i; var auto oms) in node.onMatchStatements do -:4025: { -:4026: // used by `continue on` 1232:4027: oms.ir = (caseBr.ptr[i] = instrBuilder.appendBasicBlock(currentFunction)):u8*; -:4028: } 256:4029: if node.breakOns.length do -:4030: { 4:4031: endBr = instrBuilder.appendBasicBlock(currentFunction); 16:4032: each:[function[B](B bos) => bos.ir = endBr:u8*](node.breakOns); -:4033: } 256:4034: foreach const auto cos in node.continueOns do -:4035: { 19:4036: if cos.isElseTargeted do 7:4037: cos.ir = elseBr:u8*; 12:4038: else do foreach const auto oms in node.onMatchStatements do -:4039: { 51:4040: if cos.realTarget:u8* == oms:u8* do 12:4041: break cos.ir = oms.ir; -:4042: } -:4043: } 256:4044: foreach (const auto i; const auto oms) in node.onMatchStatements do -:4045: { 1232:4046: startBlock(caseBr.ptr[i]); 1232:4047: if doCover && !oms.blockStatement.statements.length do 2:4048: cover(oms.startPos); 1232:4049: foreach (const auto j; const auto ome) in oms.onMatchExpressions do -:4050: { 1426:4051: resetAndVisitExp(ome); 1426:4052: var auto re = asRangeExp(ome); 1426:4053: if !re do -:4054: { 1342:4055: instrBuilder.addCase(currentSwitch, exp, caseBr.ptr[i]); -:4056: } -:4057: else do -:4058: { 84:4059: var auto t = LLVMTypeOf(exp); 84:4060: const auto firstInt = getIntLiteral(re.left); 84:4061: const auto lastInt = getIntLiteral(re.right); 84:4062: foreach const auto c in firstInt.value .. lastInt.value + 1 do 952:4063: instrBuilder.addCase(currentSwitch, constBuilder.int(t, c, false), caseBr.ptr[i]); -:4064: } 1426:4065: if j == oms.onMatchExpressions.length - 1 do -:4066: { 1232:4067: visitBlockStatement(oms.blockStatement); 1232:4068: if oms.flow.isContinueToNext() do -:4069: { 706:4070: endBr ?= instrBuilder.appendBasicBlock(currentFunction); 706:4071: instrBuilder.br(endBr); -:4072: } -:4073: } -:4074: } -:4075: } -:4076: -:4077: // default 256:4078: startBlock(elseBr); 256:4079: if node.elseBlock do -:4080: { 229:4081: if doCover && !node.elseBlock.statements.length do 1:4082: cover(node.elseBlock.startPos); 229:4083: visitBlockStatement(node.elseBlock); 229:4084: if node.elseBlock.flow.isContinueToNext() do -:4085: { 89:4086: endBr ?= instrBuilder.appendBasicBlock(currentFunction); 89:4087: instrBuilder.br(endBr); -:4088: } -:4089: } 27:4090: else do if AdditionalCheck.switches in session.additionalChecks && !node.fullCov do -:4091: { 13:4092: switchSpecifier ?= instrBuilder.globalStringPtr(unitNode.scope.filename ~ ":%d:%d: runtime error, switch match `%llu` is not covered\n\0"); 13:4093: var auto lineCol = getLineCol(node.expression.startPos); 13:4094: generateCheckFail([switchSpecifier, lineCol[0], lineCol[1], trapExp]); -:4095: } -:4096: else do -:4097: { 14:4098: if node.flow.isReturn() do 3:4099: instrBuilder.unreachable(); -:4100: else do -:4101: { 11:4102: endBr ?= instrBuilder.appendBasicBlock(currentFunction); 11:4103: instrBuilder.br(endBr); -:4104: } -:4105: } 256:4106: if endBr do -:4107: { 138:4108: startBlock(endBr); -:4109: } 256:4110: currentSwitch = oldSwitch; 256:4111: } -:4112: -:4113: @override function visitThisExpression(const ThisExpression* node) -:4114: { 2793:4115: visitIdentExpression(node:IdentExpression*); 2793:4116: } -:4117: -:4118: function visitTupleDeconstruction(TupleExpression* lhs; LLVMValueRef rhs; const bool nested = false) -:4119: { 19:4120: const bool isRightLvalue = LLVMGetTypeKind(LLVMTypeOf(rhs)) == LLVMTypeKind.PointerTypeKind; 19:4121: const auto ta = getTypeIr(lhs.type); 19:4122: foreach (const auto i; const auto e) in lhs.expressions do -:4123: { 82:4124: if var auto te = asTupleExp(e) do -:4125: { 3:4126: var auto val = isRightLvalue ? instrBuilder.structGep(ta, rhs, i) 3:4127: else instrBuilder.extractValue(rhs, i); 3:4128: visitTupleDeconstruction(te, val, true); -:4129: } -:4130: else do -:4131: { 38:4132: var auto val = isRightLvalue ? instrBuilder.load(getTypeIr(e.type), instrBuilder.structGep(ta, rhs, i)) 38:4133: else instrBuilder.extractValue(rhs, i); 38:4134: var auto ptr = resetAndVisitExp(e); 38:4135: rcaDecrement(e, ptr); 38:4136: instrBuilder.store(val, ptr); 38:4137: rcaIncrement(e, ptr); -:4138: } -:4139: } -:4140: // produce a valid exp in case of chained assign 19:4141: if !nested do 16:4142: visitTupleExpression(lhs); 19:4143: } -:4144: -:4145: @override function visitTupleExpression(TupleExpression* node) -:4146: { -:4147: var LLVMValueRef result; 129:4148: var auto ts = asTypeStruct(node.type); 129:4149: var auto ta = ts ? node.type.asTypeTuple(); 129:4150: if node.value do -:4151: { 75:4152: visitVariableDeclaration(node.value); 75:4153: result = nodeIRtoValueRef(node.value); -:4154: } -:4155: // rvalue tuple 129:4156: if !node.value do -:4157: { 54:4158: var auto exps = (new LLVMValueRef[+])(node.expressions.length); 54:4159: foreach (const auto i; const auto e) in node.expressions do -:4160: { 108:4161: resetAndVisitExp(e); 108:4162: exps.ptr[i] = loadExpIfLvalue(e); -:4163: } 54:4164: result = ts ? constBuilder.namedStruct(getTypeIr(ts), exps) else constBuilder.structInContext(ctxt, exps); -:4165: } -:4166: // lvalue tuple 75:4167: else do foreach (const auto i; const auto e) in node.expressions do -:4168: { 179:4169: resetAndVisitExp(e); 179:4170: exp = loadExpIfLvalue(e); 179:4171: var auto ptr = instrBuilder.structGep(getTypeIr(ta), result, i); 179:4172: instrBuilder.store(exp, ptr); -:4173: } 129:4174: exp = result; 129:4175: } -:4176: 1590:4177: @override function visitTypeExpression(TypeExpression* node){} -:4178: -:4179: @override function visitTypeAppliedGeneric(const TypeAppliedGeneric* node) -:4180: { -:4181: assert(0); -:4182: } -:4183: -:4184: @override function visitTypeAuto(const TypeAuto* node) -:4185: { -:4186: assert(0, "should have been solved during semantic"); -:4187: } -:4188: -:4189: @override function visitTypeBool(TypeBool* node) -:4190: { 15434:4191: if node.ir do 15151:4192: return; -:4193: // the front-end uses 1 to be more correct in impConv() 283:4194: node.size = 8; 283:4195: var auto t = LLVMInt1TypeInContext(ctxt); 283:4196: setTypeIr(node, t, constBuilder.int(t, 0, false)); 283:4197: setBasicTypeDi(node, DWARF_ENCODING.boolean, LLVMDIFlags.Zero); 283:4198: setVisited(node); 283:4199: } -:4200: -:4201: @override function visitTypeClass(TypeClass* node) -:4202: { 52736:4203: if node.ir do 48917:4204: return; 3819:4205: visitClassDeclaration(node.declaration); 3819:4206: setVisited(node); 3819:4207: } -:4208: -:4209: @override function visitTypeElements(const TypeElements* node) -:4210: { -:4211: assert(0); -:4212: } -:4213: -:4214: @override function visitTypeEnum(TypeEnum* node) -:4215: { 1233:4216: if node.ir do 863:4217: return; 370:4218: visitConcreteType(node.declaration.type); 370:4219: var auto ie = asIntegerExp(node.declaration.min); 370:4220: var auto t = getTypeIr(node.declaration.type); 370:4221: var auto def = constBuilder.int(t, ie.value, false); 370:4222: setTypeIr(node, t, def); 370:4223: setVisited(node); -:4224: 370:4225: if diGenerate do -:4226: { -:4227: var LLVMMetadataRef[+] elems; 341:4228: var TypeEnum* te = node; 341:4229: while te do -:4230: { 369:4231: const auto j = elems.length; 369:4232: elems.length += te.declaration.members.length; 369:4233: const bool isSigned = te.declaration.type.isSigned(); 369:4234: foreach (const auto i; const auto em) in te.declaration.members do 9543:4235: elems[j + i] = diBuilder.createEnumMember(em.name.text(), getIntLiteral(em.value).value, isSigned); 369:4236: te = te.declaration.base:u8* ? te.declaration.base.asTypeEnum() else null; -:4237: } 341:4238: var auto name = node.declaration.name.text(); -:4239: // use the unit scope, not the actual scope, because of -:4240: // https://bugs.llvm.org/show_bug.cgi?id=52363 341:4241: node.dbgIr = diBuilder.createEnumerationType(diUnitRef, name, node.startPos.line, node.size, 0, elems, getTypeDi(node.declaration.type.resolved())):u8*; -:4242: } 370:4243: } -:4244: -:4245: @override function visitTypeEnumSet(TypeEnumSet* node) -:4246: { 404:4247: if node.ir do 161:4248: return; 243:4249: visitConcreteType(node.declaration.type); 243:4250: setTypeIr(node, getTypeIr(node.declaration.type), getTypeInitIr(node.declaration.type)); 243:4251: node.dbgIr = getTypeDi(node.declaration.type):u8*; 243:4252: setVisited(node); 243:4253: } -:4254: -:4255: @override function visitTypeF32(TypeF32* node) -:4256: { 302:4257: if node.ir do 19:4258: return; 283:4259: var auto t = LLVMFloatTypeInContext(ctxt); 283:4260: setTypeIr(node, t, constBuilder.real(t, 0.0)); 283:4261: setBasicTypeDi(node, DWARF_ENCODING.float, LLVMDIFlags.Zero); 283:4262: setVisited(node); 283:4263: } -:4264: -:4265: @override function visitTypeF64(TypeF64* node) -:4266: { 441:4267: if node.ir do 158:4268: return; 283:4269: var auto t = LLVMDoubleTypeInContext(ctxt); 283:4270: setTypeIr(node, t, constBuilder.real(t, 0.0)); 283:4271: setBasicTypeDi(node, DWARF_ENCODING.float, LLVMDIFlags.Zero); 283:4272: setVisited(node); 283:4273: } -:4274: -:4275: @override function visitTypeFunction(TypeFunction* node) -:4276: { 123:4277: if node.ir do 8:4278: return; -:4279: 115:4280: var auto fd = node.declaration; 115:4281: visitConcreteType(fd.returnType); 115:4282: const auto isVariadic = FunctionFlag.isCeeVariadic in fd.flags; 115:4283: const auto paramIrCnt = fd.parameters.length:u32; 232:4284: alias mapParamTypeIr = function[T](T t): auto => {visitVariableDeclaration(t); return t.isVar() ? getPointerTypeIr(t.type) else getTypeIr(t.type);}; 115:4285: var auto paramT = map:[mapParamTypeIr](fd.parameters); 115:4286: var auto retT = fd.isVar() ? getPointerTypeIr(fd.returnType) else getTypeIr(fd.returnType); 115:4287: var auto tf = LLVMFunctionType(retT, paramT.ptr, paramIrCnt, isVariadic); 115:4288: setTypeIr(node, tf, null); 115:4289: setVisited(node); 115:4290: setUnspecifiedTypeDi(node); 115:4291: } -:4292: -:4293: @override function visitTypeIdentifier(const TypeIdentifier* node) -:4294: { 46203:4295: visitConcreteType(node.resolved()); 46203:4296: } -:4297: -:4298: @override function visitTypeNull(TypeNull* node) -:4299: { 70:4300: if node.ir do 62:4301: return; 8:4302: setTypeIr(node, getPointerTypeIr(TypeU8.instance()), null); 8:4303: setUnspecifiedTypeDi(node); 8:4304: setVisited(node); 8:4305: } -:4306: -:4307: @override function visitTypePointer(TypePointer* node) -:4308: { 78277:4309: if node.ir do 20601:4310: return; 57676:4311: visitConcreteType(node.modified); 57676:4312: var auto tt = getTypeIr(node.modified); 57676:4313: var auto t = LLVMPointerType(tt, 0); 57676:4314: setTypeIr(node, t, constBuilder.$null(t)); 57676:4315: setVisited(node); 57676:4316: if diGenerate do 51677:4317: node.dbgIr = diBuilder.createPointerType(getTypeDi(node.modified.resolved()), session.ptr_size, 8, format(node)):u8*; 57676:4318: } -:4319: -:4320: @override function visitTypeRcArray(TypeRcArray* node) -:4321: { 4726:4322: if node.ir do 2495:4323: return; 2231:4324: visitConcreteType(node.modified); 2231:4325: setTypeIr(node, rcaType, constBuilder.$null(rcaType)); 2231:4326: if diGenerate do -:4327: { 1641:4328: if !rcaTypeDi do -:4329: { 41:4330: var auto m0 = diBuilder.createMemberType(diScope, "refcount", node.startPos.line, session.ptr_size, 0, 0, LLVMDIFlags.Zero, getTypeDi(TypeUSize())); 41:4331: var auto m1 = diBuilder.createMemberType(diScope, "length", node.startPos.line, session.ptr_size, 0, session.ptr_size, LLVMDIFlags.Zero, getTypeDi(TypeUSize())); 41:4332: rcaTypeDi = diBuilder.createStructType(diUnitRef, "RCArray", 0, session.ptr_size * 2, 8, LLVMDIFlags.Zero, [m0, m1]); -:4333: } 1641:4334: var auto name = format(node); 1641:4335: node.dbgIr = diBuilder.createPointerType(rcaTypeDi, session.ptr_size, 8, name):u8*; -:4336: } 2231:4337: setVisited(node); 2231:4338: } -:4339: -:4340: @override function visitTypeS16(TypeS16* node) -:4341: { 312:4342: if node.ir do 29:4343: return; 283:4344: var auto t = LLVMInt16TypeInContext(ctxt); 283:4345: setTypeIr(node, t, constBuilder.int(t, 0, true)); 283:4346: setBasicTypeDi(node, DWARF_ENCODING.signed, LLVMDIFlags.Zero); 283:4347: setVisited(node); 283:4348: } -:4349: -:4350: @override function visitTypeS32(TypeS32* node) -:4351: { 3399:4352: if node.ir do 3116:4353: return; 283:4354: var auto t = LLVMInt32TypeInContext(ctxt); 283:4355: setTypeIr(node, t, constBuilder.int(t, 0, true)); 283:4356: setBasicTypeDi(node, DWARF_ENCODING.signed, LLVMDIFlags.Zero); 283:4357: setVisited(node); 283:4358: } -:4359: -:4360: @override function visitTypeS64(TypeS64* node) -:4361: { 1266:4362: if node.ir do 983:4363: return; 283:4364: var auto t = LLVMInt64TypeInContext(ctxt); 283:4365: setTypeIr(node, t, constBuilder.int(t, 0, true)); 283:4366: setBasicTypeDi(node, DWARF_ENCODING.signed, LLVMDIFlags.Zero); 283:4367: setVisited(node); 283:4368: } -:4369: -:4370: @override function visitTypeS8(TypeS8* node) -:4371: { 7389:4372: if node.ir do 7106:4373: return; 283:4374: var auto t = LLVMInt8TypeInContext(ctxt); 283:4375: setTypeIr(node, t, constBuilder.int(t, 0, true)); 283:4376: setBasicTypeDi(node, DWARF_ENCODING.signed, LLVMDIFlags.Zero); 283:4377: setVisited(node); 283:4378: } -:4379: -:4380: @override function visitTypeSlice(TypeSlice* node) -:4381: { 5376:4382: if node.ir do 2166:4383: return; -:4384: 3210:4385: visitConcreteType(node.modified); 3210:4386: var auto tp = getPointerTypeIr(node.modified); 3210:4387: var auto tl = getTypeIr(TypeUSize()); 3210:4388: var auto td = LLVMStructTypeInContext(ctxt, [tl, tp].ptr, 2, false); 3210:4389: setTypeIr(node, td, constBuilder.zeroInit(td)); 3210:4390: setVisited(node); 3210:4391: if diGenerate do -:4392: { 1948:4393: var auto name = format(node); 1948:4394: var auto po = diBuilder.createPointerType(getTypeDi(node.modified.resolved()), session.ptr_size, 8, format(node.modified.resolved())); 1948:4395: var auto m1 = diBuilder.createMemberType(diScope, "length", node.startPos.line, session.ptr_size, 0, 0, LLVMDIFlags.Zero, getTypeDi(TypeUSize())); 1948:4396: var auto m2 = diBuilder.createMemberType(diScope, "ptr", node.startPos.line, session.ptr_size, 0, session.ptr_size, LLVMDIFlags.Zero, po); 1948:4397: node.dbgIr = diBuilder.createStructType(diUnitRef, name, node.startPos.line, node.size, 0, LLVMDIFlags.Zero, [m1,m2]):u8*; -:4398: } 3210:4399: } -:4400: -:4401: @override function visitTypeStaticArray(TypeStaticArray* node) -:4402: { 5537:4403: if node.ir do 559:4404: return; -:4405: 4978:4406: var auto mt = node.modified.resolved(); 4978:4407: visitConcreteType(mt); 4978:4408: const auto len = node.length():u32; 4978:4409: var auto et = getTypeIr(mt); 4978:4410: var auto at = LLVMArrayType(et, len); -:4411: -:4412: var LLVMValueRef i; 4978:4413: if mt.asTypeAggregate() do -:4414: { 5:4415: var auto s = getTypeInitIr(mt); 5:4416: var auto g = (new LLVMValueRef[+])(len); 5:4417: g[] = s; 5:4418: i = constBuilder.array(et, g); -:4419: } 4973:4420: else do i = constBuilder.zeroInit(at); -:4421: 4978:4422: setTypeIr(node, at, i); 4978:4423: setVisited(node); 4978:4424: if diGenerate do 4463:4425: node.dbgIr = diBuilder.createArrayType(node.length(), 0, getTypeDi(node.modified.resolved())):u8*; 4978:4426: } -:4427: -:4428: @override function visitTypeStruct(TypeStruct* node) -:4429: { 9755:4430: if node.ir do 9528:4431: return; 227:4432: visitStructDeclaration(node.declaration); 227:4433: setVisited(node); 227:4434: } -:4435: -:4436: @override function visitTypeTuple(TypeTuple* node) -:4437: { 459:4438: if node.ir do 334:4439: return; 556:4440: alias fun = function[T](T t):auto => {visitConcreteType(t); return getTypeIr(t);}; 125:4441: var auto types = map:[fun](node.types); 125:4442: var auto s = LLVMStructTypeInContext(ctxt, types.ptr, types.length:u32, false); 125:4443: setTypeIr(node, s, constBuilder.zeroInit(s)); -:4444: 125:4445: if diGenerate do -:4446: { 101:4447: var auto diMembers = (new LLVMMetadataRef[+])(node.types.length); -:4448: var u32 offset; 101:4449: foreach (const auto i; const auto t) in node.types do -:4450: { 220:4451: var auto size = t.size; 220:4452: var auto mtype = t.resolved(); 220:4453: var auto mname = "[" ~ u32ToString(i:u32) ~ "]"; -:4454: 220:4455: switch size do -:4456: { 112:4457: on 32 do offset += -offset & 31; 5:4458: on 16 do offset += -offset & 15; 12:4459: on 8 do {} 91:4460: else do offset += -offset & (session.ptr_size - 1):u32; -:4461: } -:4462: 220:4463: diMembers[i] = diBuilder.createMemberType(diScope, mname, node.startPos.line, -:4464: size, mtype.align, offset, LLVMDIFlags.Zero, getTypeDi(mtype)); 220:4465: offset += size; -:4466: } -:4467: 101:4468: const auto linkageName = Token.generateIdentifier().text(); 101:4469: node.dbgIr = diBuilder.createStructType(diUnitRef, linkageName, -:4470: node.startPos.line, node.size, 0, LLVMDIFlags.Zero, diMembers):u8*; -:4471: } -:4472: 125:4473: setVisited(node); 125:4474: } -:4475: -:4476: @override function visitTypeU16(TypeU16* node) -:4477: { 885:4478: if node.ir do 602:4479: return; 283:4480: var auto t = LLVMInt16TypeInContext(ctxt); 283:4481: setTypeIr(node, t, constBuilder.int(t, 0, false)); 283:4482: setBasicTypeDi(node, DWARF_ENCODING.unsigned, LLVMDIFlags.Zero); 283:4483: setVisited(node); 283:4484: } -:4485: -:4486: @override function visitTypeU32(TypeU32* node) -:4487: { 11937:4488: if node.ir do 11654:4489: return; 283:4490: var auto t = LLVMInt32TypeInContext(ctxt); 283:4491: setTypeIr(node, t, constBuilder.int(t, 0, false)); 283:4492: setBasicTypeDi(node, DWARF_ENCODING.unsigned, LLVMDIFlags.Zero); 283:4493: setVisited(node); 283:4494: } -:4495: -:4496: @override function visitTypeU64(TypeU64* node) -:4497: { 10946:4498: if node.ir do 10663:4499: return; 283:4500: var auto t = LLVMInt64TypeInContext(ctxt); 283:4501: setTypeIr(node, t, constBuilder.int(t, 0, false)); 283:4502: setBasicTypeDi(node, DWARF_ENCODING.unsigned, LLVMDIFlags.Zero); 283:4503: setVisited(node); 283:4504: } -:4505: -:4506: @override function visitTypeU8(TypeU8* node) -:4507: { 54420:4508: if node.ir do 54137:4509: return; 283:4510: var auto t = LLVMInt8TypeInContext(ctxt); 283:4511: setTypeIr(node, t, constBuilder.int(t, 0, false)); 283:4512: setBasicTypeDi(node, DWARF_ENCODING.unsigned, LLVMDIFlags.Zero); 283:4513: setVisited(node); 283:4514: } -:4515: -:4516: @override function visitTypeUnion(TypeUnion* node) -:4517: { 30:4518: if node.ir do 17:4519: return; -:4520: 13:4521: const auto d = node.declaration; 13:4522: visitUnionDeclaration(d); 13:4523: const auto t = d.ir:LLVMTypeRef; 13:4524: setTypeIr(node, t, constBuilder.zeroInit(t)); 13:4525: setVisited(node); -:4526: 13:4527: if diGenerate do -:4528: { 1:4529: var auto diMembers = getMemberDi(d.symbol); 1:4530: node.dbgIr = diBuilder.createUnionType(diUnitRef, d.linkageName, node.startPos.line, node.size, node.align, LLVMDIFlags.Zero, diMembers):u8*; -:4531: } 13:4532: } -:4533: -:4534: @override function visitTypeVoid(TypeVoid* node) -:4535: { 35767:4536: if node.ir do 35484:4537: return; 283:4538: setTypeIr(node, LLVMVoidTypeInContext(ctxt), null); 283:4539: setUnspecifiedTypeDi(node); 283:4540: setVisited(node); 283:4541: } -:4542: -:4543: @override function visitUnionDeclaration(UnionDeclaration* node) -:4544: { 28:4545: if node.nextInstance do 3:4546: visitConcreteDeclaration(node.nextInstance); 28:4547: if node.isGeneric() do 1:4548: return; 27:4549: const DeclModuleInfo di = getDeclModuleInfo(node); 27:4550: if di.isVisited do 14:4551: return; 13:4552: var auto oldAggregateType = currentAggregateType; 13:4553: var s8[+] linkageName = node.linkageName; 13:4554: currentAggregateType = LLVMStructCreateNamed(ctxt, (linkageName ~ "\0").ptr); 13:4555: node.ir = currentAggregateType:u8*; 13:4556: const auto oldPass = pass; 13:4557: pass = 0; 25:4558: if node.body do visitDeclarations(node.body); 13:4559: pass = oldPass; -:4560: // create an opaque member with for size the union size. -:4561: // reading members will simply cast the whole variable. -:4562: var LLVMTypeRef fillerType; 13:4563: var u32 size = node.asTypeDeclared.size / 8; 13:4564: switch size do -:4565: { 2:4566: on 1 do fillerType = getTypeIr(TypeU8.instance()); 1:4567: on 2 do fillerType = getTypeIr(TypeU16.instance()); 2:4568: on 4 do fillerType = getTypeIr(TypeU32.instance()); 5:4569: on 8 do fillerType = getTypeIr(TypeU64.instance()); 3:4570: else do fillerType = LLVMArrayType(getTypeIr(TypeU8.instance()), size); -:4571: } 13:4572: LLVMStructSetBody(currentAggregateType, &fillerType, 1, false); 13:4573: currentAggregateType = oldAggregateType; 13:4574: } -:4575: -:4576: function findStaticCtorDtors() -:4577: { -:4578: @final class StaticCtorDtorListBuilder : AstVisitor -:4579: { -:4580: static var LLVMIrGen* irgen; -:4581: 72:4582: @override function visitExpression(Expression* node){} -:4583: 245:4584: @override function visitType(Type* node){} -:4585: -:4586: @override function visitDeclaration(Declaration* node) -:4587: { 6865:4588: if node.nextInstance do 128:4589: visitDeclaration(node.nextInstance); 6865:4590: if !node.genericParameters || node.genericParameters.applied() do 6793:4591: switch node.kind do -:4592: { -:4593: on $class, $struct, $function, $union, $version do 5202:4594: visitConcreteDeclaration(node); 1591:4595: else do {} -:4596: } 6865:4597: } -:4598: -:4599: @override function visitFunctionDeclaration(FunctionDeclaration* node) -:4600: { 4281:4601: if FunctionFlag.isStaticCtor in node.flags do 14:4602: irgen.staticCtors ~= node; 4267:4603: else do if FunctionFlag.isStaticDtor in node.flags do 60:4604: irgen.staticDtors ~= node; 4281:4605: } -:4606: } -:4607: var StaticCtorDtorListBuilder b; 283:4608: StaticCtorDtorListBuilder.irgen = this; 283:4609: b.visitDeclarations(unitNode.declarations); 283:4610: } -:4611: -:4612: @override function visitUnitDeclaration(UnitDeclaration* node) -:4613: { 283:4614: diGenerate = session.generateDebugInfo; 283:4615: ctxt = LLVMContextCreate(); 283:4616: unitNode = node; 283:4617: moduleString = tokenChainText(node.identifiers.asTypeIdentifier().chain()) ~ "\0"; 283:4618: unitIr = LLVMModuleCreateWithNameInContext(moduleString.ptr, ctxt); 283:4619: unitNode.ir = unitIr:u8*; 283:4620: instrBuilder = (new InstrBuilder).create(ctxt); 283:4621: isRtlRootUnit = node.identifiers.identifier.iptr() == rtlToken().iptr(); -:4622: 283:4623: findStaticCtorDtors(); 283:4624: initializeDI(); 283:4625: initialize(); -:4626: 283:4627: if session.cover do -:4628: { 10:4629: doCover = true; 10:4630: visitVariableDeclaration(node.coverData); 10:4631: coverArrayIr = nodeIRtoValueRef(node.coverData); 10:4632: coverArrayInit.length = unitNode.stopPos.line; 10:4633: coverArrayInit[] = minusOne32; -:4634: } -:4635: 282:4636: visitDeclarations(node.declarations); -:4637: 282:4638: pass++; -:4639: -:4640: var usize i; 282:4641: while i < functions.length() do 35159:4642: visitFunctionDeclaration(functions[i++]); -:4643: 282:4644: if doCover do -:4645: { -:4646: // finalize the initializer 10:4647: var auto a = nodeIRtoValueRef(unitNode.coverData); 10:4648: var auto b = constBuilder.array(getTypeIr(TypeU32.instance()), coverArrayInit); 10:4649: LLVMSetInitializer(a, b); -:4650: // add a final dtor that call the rtl func responsible for writing data file 10:4651: coverageRtlFinalizer(); -:4652: } -:4653: 282:4654: generateStaticCtorsSpecialVariable(); 282:4655: generateStaticDtorsSpecialVariable(); 9222:4656: each:[function[T](T ad) => fixupVtable(ad)](vtableOwners); 9222:4657: each:[function[T](T ad) => ad.vtableVar.ir = null](vtableOwners); -:4658: 169168:4659: foreach const auto v in visited do -:4660: { 168886:4661: v.ir = null; 337772:4662: if var auto d = v.asDeclaration() do 87527:4663: d.progress = done; 162718:4664: else do if var auto t = v.asType() do 81359:4665: t.dbgIr = null; -:4666: } -:4667: 82224:4668: each:[function[T](T fd) => fd.ir = null](functions2); 9212:4669: each:[function[T](T vd) => vd.context = VariableDeclarationContext.parameter](copiedToLocal); 282:4670: var s8[+] fname = unitNode.identifiers.asTypeIdentifier().chain().tokenChainText(); -:4671: 282:4672: if session.beDir.length do -:4673: { 282:4674: if !session.beDir.exists() do 2:4675: createDir(session.beDir); 282:4676: fname = session.beDir ~ "/" ~ fname; -:4677: } 282:4678: finalizeDI(); -:4679: 282:4680: const BackendOutputKind be = session.beKind; -:4681: // 1. skip rtl.sx because `__sx_finalize_cov` is slow to compile and to verify -:4682: // 2. skip verif when targeting ll files because IR output is meant to be verified manually 282:4683: if !isRtlRootUnit && be != BackendOutputKind.ir && ir in session.additionalChecks do -:4684: { -:4685: var s8* msg; 193:4686: if session.verbose do printf("verifying IR of unit %s...\n", moduleString.ptr); 192:4687: if LLVMVerifyModule(unitIr, LLVMVerifierFailureAction.ReturnStatusAction, &msg) == 1 do -:4688: { 1:4689: printf("error, the IR for unit %s is invalid\n", moduleString.ptr); 1:4690: if msg do 1:4691: displayError(msg); 1:4692: successFlag = false; 1:4693: return; -:4694: } -:4695: } -:4696: 282:4697: if session.optLevel do optimize(unitIr); -:4698: 281:4699: switch be do -:4700: { 1:4701: on bc do successFlag = outputBC(unitIr, fname); 7:4702: on ir do successFlag = outputIR(unitIr, fname); 1:4703: on $asm do successFlag = outputOBJ(unitIr, fname, true); 272:4704: on ar, exe, obj do successFlag = outputOBJ(unitIr, fname, false); -:4705: } -:4706: 281:4707: delete instrBuilder; 281:4708: LLVMDisposeModule(unitIr); 281:4709: LLVMContextDispose(ctxt); 281:4710: } -:4711: -:4712: @override function visitVariableDeclaration(VariableDeclaration* node) -:4713: { 177095:4714: const DeclModuleInfo di = getDeclModuleInfo(node); 177095:4715: if di.isVisited do 120082:4716: return; -:4717: -:4718: //////////// -:4719: // first create the IR, as the init may require it (ctor) 57013:4720: visitConcreteType(node.type); 57013:4721: const auto ty = getTypeIr(node.type); -:4722: 57013:4723: const auto isStatic = node.isStatic(); 57013:4724: if node.symbol.parent.kind in unitKinds || isStatic do // global, static member, static local -:4725: { 868:4726: var auto linkageName = node.linkageName; 868:4727: node.ir = LLVMAddGlobal(unitIr, ty, (linkageName ~ "\0").ptr):u8*; 868:4728: if diGenerate do -:4729: { 710:4730: var auto type = getTypeDi(node.type.resolved()); 710:4731: var auto m2 = diBuilder.createGlobalVariableExpression(diUnitRef, node.name.text(), linkageName, node.startPos.line, type, false, 8); 710:4732: LLVMGlobalSetMetadata(nodeIRtoValueRef(node), 0, m2); // no magic constant for 0 => "!dbg" in the C API -:4733: } -:4734: } 56145:4735: else do if node.symbol.parent.kind in aggregateKinds do // non-static member -:4736: { -:4737: } -:4738: // param: either copied later, or directly read from using LLVMGetParam() 47153:4739: else do if node.isParameter || isImmediate in node.flags do -:4740: { -:4741: } -:4742: else do -:4743: { -:4744: // locals IR are mostly set on function entry, e.g prevent stackoverflow in loops -:4745: // the exception is for generated temporaries, which are not part of the AST 6991:4746: node.ir ?= instrBuilder.alloca(ty):u8*; 6991:4747: if diGenerate do -:4748: { 3803:4749: var auto name = node.name.text(); 3803:4750: var auto type = getTypeDi(node.type.resolved()); 3803:4751: var auto v1 = instrBuilder.metadataAsValue(LLVMValueAsMetadata(nodeIRtoValueRef(node))); 3803:4752: var auto m2 = diBuilder.createLocalVariable(diScope, name, node.startPos.line, type, LLVMDIFlags.Zero, 8); 3803:4753: var auto v2 = instrBuilder.metadataAsValue(m2); 3803:4754: var auto v3 = instrBuilder.metadataAsValue(diBuilder.createDummyExpression()); 3803:4755: var auto e = instrBuilder.call(llvm_dbg_declare().tupleof, [v1, v2, v3]); 3803:4756: instructionDi(node, e); -:4757: } -:4758: } -:4759: 57013:4760: if isStatic do -:4761: { 830:4762: const auto tlsMode = node.getAtTLS() ? LLVMThreadLocalMode.GeneralDynamicTLSModel else LLVMThreadLocalMode.NotThreadLocal; 830:4763: LLVMSetThreadLocalMode(nodeIRtoValueRef(node), tlsMode); -:4764: } 57013:4765: const auto isForeign = node.getAtForeign():u8* != null; 57013:4766: if (di.isImported || isForeign) && isStatic do 565:4767: return LLVMSetLinkage(nodeIRtoValueRef(node), LLVMLinkage.ExternalLinkage); -:4768: -:4769: //////////// -:4770: // then handle the initializer, if it uses the node.ir this wont loop + SEGFAULT 56448:4771: exp = null; 56448:4772: var auto initializer = node.initializer; 56448:4773: var auto tsa = node.type.asTypeStaticArray(); 56448:4774: const auto isNoLengthSta = tsa && tsa.length() == 0; 56448:4775: if node.initializer && !isNoLengthSta do -:4776: { -:4777: // func used as init must have an IR on first pass 6061:4778: const auto old = pass; 6061:4779: pass = 1; -:4780: // if parameter init contains a call, this call needs to be in the caller frame 6061:4781: if !node.isParameter do -:4782: { 4279:4783: if !di.isImported && doCover && currentFunction do cover(initializer.startPos); 4093:4784: visitConcreteExpression(initializer); -:4785: } 6061:4786: pass = old; -:4787: // b/c of `nodeIRtoValueRef(initializer)` in getInitializer 6061:4788: initializer.ir = exp:u8*; -:4789: } -:4790: 56448:4791: if node.symbol.parent.kind in unitKinds || isStatic do -:4792: { 303:4793: var auto i = getInitializer(node); 303:4794: const bool isStaticLocal = isStatic && currentFunction && initializer && !initializer.canInitialize(); 303:4795: if isStaticLocal do -:4796: { 1:4797: LLVMSetInitializer(nodeIRtoValueRef(node), constBuilder.undef(ty)); 1:4798: instrBuilder.store(initializer.isLvalue() ? instrBuilder.load(ty, i) else i , nodeIRtoValueRef(node)); -:4799: } 302:4800: else do LLVMSetInitializer(nodeIRtoValueRef(node), i); -:4801: } 56145:4802: else do if node.symbol.parent.kind in aggregateKinds do -:4803: { -:4804: } -:4805: // param: either copied later, or directly read using LLVMGetParam() 47153:4806: else do if node.isParameter do -:4807: { -:4808: } 8697:4809: else do if !isNoLengthSta do -:4810: { 8695:4811: if initializer do -:4812: { 3750:4813: loadExpIfLvalue(initializer); 3750:4814: if isImmediate in node.flags do 1186:4815: initializer.ir = exp:u8*; -:4816: else do -:4817: { 2564:4818: var auto e = instrBuilder.store(exp, nodeIRtoValueRef(node)); 2564:4819: instructionDi(initializer, e); 2564:4820: rcaIncrement(initializer, nodeIRtoValueRef(node)); -:4821: } -:4822: } -:4823: // init using the type-specific initializer 4945:4824: else do if !node.getAtNoinit() && isImmediate !in node.flags && 4371:4825: (isTemp !in node.flags || skipManagment !in node.flags || asTypeSlice(node.type)) do -:4826: { 4258:4827: instrBuilder.store(getInitializer(node), nodeIRtoValueRef(node)); -:4828: } -:4829: } 56448:4830: } -:4831: -:4832: @override function visitVersionBlockDeclaration(VersionBlockDeclaration* node) -:4833: { 97:4834: if node.thenDeclarations do 62:4835: visitDeclarations(node.thenDeclarations); 35:4836: else do if node.elseDeclarations do 2:4837: visitDeclarations(node.elseDeclarations); 97:4838: } -:4839: -:4840: @override function visitVersionBlockStatement(VersionBlockStatement* node) -:4841: { 24:4842: if node.thenBlock do 18:4843: visitBlockStatement(node.thenBlock); 6:4844: else do if node.elseBlock do 4:4845: visitBlockStatement(node.elseBlock); 24:4846: } -:4847: -:4848: @override function visitWhileStatement(WhileStatement* node) -:4849: { 451:4850: var auto testBr = instrBuilder.appendBasicBlock(currentFunction); 451:4851: var auto loopBr = instrBuilder.appendBasicBlock(currentFunction); 451:4852: var auto endBr = instrBuilder.appendBasicBlock(currentFunction); -:4853: 491:4854: if doCover do cover(node.startPos); -:4855: 451:4856: node.ir = (new LoopBlockRefIr).create(testBr, endBr):u8*; -:4857: 451:4858: instrBuilder.br(testBr); 451:4859: startBlock(testBr); 451:4860: resetAndVisitExp(node.condition); 451:4861: exp = loadExpIfLvalue(node.condition); 451:4862: instrBuilder.condBr(exp, loopBr, endBr); -:4863: 451:4864: startBlock(loopBr); 451:4865: visitBlockStatement(node.blockStatement); 451:4866: const Flow bodyEndFlow = node.blockStatement.flow; -:4867: 451:4868: if bodyEndFlow.containsContinueToNext() && !bodyEndFlow.isContinue() && 443:4869: !bodyEndFlow.isBreak() && !bodyEndFlow.isReturn() && !bodyEndFlow.isContinueOn() do 328:4870: instrBuilder.br(testBr); 451:4871: if !instrBuilder.getBasicBlockTerminator(currentBlock) do 1:4872: instrBuilder.br(endBr); 451:4873: startBlock(endBr); 451:4874: var auto be = asBoolExp(node.condition); 451:4875: if be && be.value && !node.flow.containsBreak() do 28:4876: instrBuilder.unreachable(); 451:4877: } -:4878: -:4879: @override function visitWithStatement(WithStatement* node) -:4880: { 16:4881: if doCover do cover(node.startPos); 20:4882: each:[function[E](E e) => resetAndVisitExp(e)](node.preExpressions); 16:4883: exp = null; 16:4884: visitBlockStatement(node.blockStatement); 16:4885: } -:4886: -:4887: @override function visitXorAssignExpression(const XorAssignExpression* node) -:4888: { 5:4889: visitBinaryAssignExpression(node); 5:4890: } -:4891: -:4892: @override function visitXorExpression(const XorExpression* node) -:4893: { 4:4894: visitBinaryExpression(node); 4:4895: } -:4896: -:4897: function visitFunctionBody(FunctionDeclaration* node) -:4898: { 4439:4899: if node.asmBody do -:4900: { 4:4901: generateAsmBody(node); 4:4902: return; -:4903: } 4435:4904: if !node.body do 487:4905: return; -:4906: -:4907: // if this fails then a case in bodiesSemantic() is not handled 3948:4908: assert(node.bodyDone); -:4909: 3948:4910: currentAsmDialect = isAsmIntel in node.flags ? LLVMInlineAsmDialect.Intel else LLVMInlineAsmDialect.ATT; 3948:4911: const bool isVariadic = FunctionFlag.isCeeVariadic in node.flags; 3948:4912: const usize requiredParamIrs = node.parameters.length; 3948:4913: var auto oldFunc = currentFunction; 3948:4914: currentFunction = nodeIRtoValueRef(node); 3948:4915: const auto wasInNestedFunc = inNestedFunc; 3948:4916: var auto oldEscapes = currentEscapes; 3948:4917: inNestedFunc = false; -:4918: -:4919: // value to apply implicit `this.`. 3948:4920: thisExp = null; 3948:4921: if requiredParamIrs && node.parameters[0].name == thisToken() do 1811:4922: thisExp = LLVMGetParam(currentFunction, 0); 3948:4923: var auto entry = instrBuilder.appendBasicBlock(currentFunction, "entry"); 3948:4924: startBlock(entry); 3948:4925: createLocalVarsAllocas(node); 3948:4926: foreach const auto vd in node.parameters do -:4927: { 5936:4928: copyParameterToReferencableLocal(vd); -:4929: // make unique copies of rc arrays that are passed by value -:4930: // e.g: `param.length += 1`, does an implicit decref, but the memory -:4931: // pointed by the argument must not be free'd 5936:4932: var auto tra = asTypeRcArray(vd.type); 5936:4933: if tra && !vd.isVar() && !vd.isConst() do -:4934: { 8:4935: var auto ptr = nodeIRtoValueRef(vd); 8:4936: var auto thisArg = instrBuilder.load(getTypeIr(vd.type), ptr); 8:4937: var auto bsz = constBuilder.int(getTypeIr(TypeU32.instance()), tra.modified.resolved().size, false); 8:4938: var auto newArr = instrBuilder.call(rtl_rcaDup().tupleof, [thisArg, bsz]); 8:4939: instrBuilder.store(newArr, ptr); -:4940: -:4941: //.dup result has a count of -1 8:4942: var auto e = instrBuilder.call(rtl_rcaIncRefCount().tupleof, [newArr]); 8:4943: instructionDi(node, e); -:4944: } -:4945: } 3948:4946: escapePrepare(node); -:4947: -:4948: // cannot be in visit(VarDecl), because -:4949: // 1. the call to `llvm_dbg_declare` requires a builder -:4950: // 2. parameters can be copied to an alloca 3948:4951: if diGenerate do -:4952: { 2121:4953: foreach (const auto i; const auto p) in node.parameters do -:4954: { 3411:4955: if isVariadic && i == node.parameters.length - 1 do 5:4956: break; 3406:4957: var auto name = p.name.text(); 3406:4958: var auto type = getTypeDi(p.type.resolved()); 3406:4959: var auto v1 = instrBuilder.metadataAsValue(LLVMValueAsMetadata(p.ir ? nodeIRtoValueRef(p) else LLVMGetParam(currentFunction, i:u32))); 3406:4960: var auto m2 = diBuilder.createParameterVariable(diScope, name, (i + 1):u32, p.startPos.line, type, LLVMDIFlags.Zero); 3406:4961: var auto v2 = instrBuilder.metadataAsValue(m2); 3406:4962: var auto v3 = instrBuilder.metadataAsValue(diBuilder.createDummyExpression()); 3406:4963: var auto e = instrBuilder.call(llvm_dbg_declare().tupleof, [v1, v2, v3]); 3406:4964: instructionDi(p, e); -:4965: } -:4966: } -:4967: 3948:4968: const bool wasCovering = doCover; 3948:4969: if node.getAtNoReturn() do doCover = false; 3948:4970: visitStatement(node.body); 3948:4971: doCover = wasCovering; 3948:4972: currentFunction = oldFunc; 3948:4973: inNestedFunc = wasInNestedFunc; 3948:4974: currentEscapes = oldEscapes; 3948:4975: } -:4976:} <<<<<< EOF # path=src/styx/backend/link.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/backend/link.sx -: 1:unit styx.backend.link; -: 2: -: 3:import -: 4: system, -: 5: styx.session, -: 6: ; -: 7: -: 8:/// Links the objects produced during the session as an executable -: 9:function linkExecutable(): bool -: 10:{ -: 11: version posix do -: 12: { -: 13: var s8[+] crtDir; -: 14: var s8[] loader; -: 15: // TODO-cDriver: add option "cstatic" to control how the c library is linked 171: 16: var s8[] libc = "-lc"; 171: 17: var s8[] librt = "-lrt"; 171: 18: var s8[] libpthread = "-lpthread"; 171: 19: var s8[] libm = "-lm"; 171: 20: var s8[] libdl = "-ldl"; -: 21: var s8* ldTgt; -: 22: var s8[][] possibleCrt1o; -: 23: var s8[][] possibleDynLd; -: 24: 171: 25: const bool useCustomLibc = session.libc.length || session.libc32.length || session.libc64.length; -: 26: 171: 27: if useCustomLibc do -: 28: { 0: 29: if session.ptr_size == 32 && session.libc32.length do 0: 30: session.libc = session.libc32; 0: 31: else do if session.ptr_size == 64 && session.libc64.length do 0: 32: session.libc = session.libc64; 0: 33: if session.libc.length && session.libc[$-1] != "/" do 0: 34: session.libc ~= "/"; -: 35: 0: 36: libc = session.libc ~ "libc.a"; 0: 37: librt = session.libc ~ "librt.a"; 0: 38: libpthread = session.libc ~ "libpthread.a"; 0: 39: libm = session.libc ~ "libm.a"; 0: 40: libdl = session.libc ~ "libdl.a"; -: 41: } -: 42: 171: 43: if session.ptr_size == 32 do -: 44: { 1: 45: ldTgt = "-melf_i386"; 1: 46: possibleCrt1o = [ "/lib/crt1.o"[], "/usr/lib/crt1.o"[], "/usr/lib32/crt1.o"[], -: 47: "/usr/lib/i386-linux-gnu/crt1.o"[] -: 48: ]; 1: 49: possibleDynLd = [ -: 50: "/lib/ld-linux.so.2"[], "/usr/lib/ld-linux.so.2"[], -: 51: "/lib/i386-linux-gnu/ld-linux.so.2"[], "/lib/ld-linux-i386.so.2"[] -: 52: ]; -: 53: } -: 54: else do -: 55: { 170: 56: ldTgt = "-melf_x86_64"; 170: 57: possibleCrt1o = [ "/lib64/crt1.o"[], "/usr/lib64/crt1.o"[], -: 58: "/usr/lib/x86_64-linux-gnu/crt1.o"[] -: 59: ]; 170: 60: possibleDynLd = [ -: 61: "/lib64/ld-linux.so.2"[], "/usr/lib64/ld-linux.so.2"[], -: 62: "/lib/x86-64-linux-gnu/ld-linux.so.2"[], "/lib64/ld-linux-x86-64.so.2"[] -: 63: ]; -: 64: } -: 65: 171: 66: if useCustomLibc do 0: 67: crtDir = session.libc; 171: 68: else do foreach var auto c in possibleCrt1o do -: 69: { 171: 70: if c.exists() do 171: 71: break crtDir = dirName(c); -: 72: } 171: 73: if !crtDir.length do -: 74: { 0: 75: printf("linking error, cannot find the location of `crt1.o`, `crti.o` and `crtn.o` \n"); 0: 76: return false; -: 77: } 171: 78: foreach var auto d in possibleDynLd do -: 79: { 681: 80: if d.exists() do 171: 81: break loader = d; -: 82: } 171: 83: if !loader.length do -: 84: { 0: 85: printf("linking error, cannot find the location of the dynamic loader (ld-linux.so) \n"); 0: 86: return false; -: 87: } -: 88: 171: 89: if !session.outputFilename.length do 170: 90: session.outputFilename = "a.out"; -: 91: -: 92: var Process p; 171: 93: p.executable = "/usr/bin/ld"; 171: 94: p.redirects = [err, out]; -: 95: 171: 96: p.arguments ~= ldTgt; 171: 97: p.arguments ~= ("-L" ~ crtDir ~ "\0").ptr; 171: 98: p.arguments ~= (crtDir ~ "/crt1.o\0").ptr; 171: 99: p.arguments ~= (crtDir ~ "/crti.o\0").ptr; -:100: 171:101: foreach var auto o in session.objects do 265:102: p.arguments ~= o.ptr; -:103: 171:104: p.arguments ~= (crtDir ~ "/crtn.o\0").ptr; 171:105: p.arguments ~= (libc ~ "\0").ptr; 171:106: p.arguments ~= (librt ~ "\0").ptr; 171:107: p.arguments ~= (libpthread ~ "\0").ptr; 171:108: p.arguments ~= (libdl ~ "\0").ptr; 171:109: p.arguments ~= (libm ~ "\0").ptr; 171:110: p.arguments ~= "-o"; 171:111: p.arguments ~= (session.outputFilename ~ "\0").ptr; -:112: 171:113: if !useCustomLibc do -:114: { 171:115: p.arguments ~= "-dynamic-linker\0"; 171:116: p.arguments ~= loader.ptr; -:117: } -:118: 171:119: foreach var auto a in session.additionalLinkerArgs do 0:120: p.arguments ~= a.ptr; -:121: -:122: var s8[+] stdOut; -:123: var s8[+] stdErr; 171:124: p.execute(); 171:125: var s32 r = p.waitAndRead(&stdOut, &stdErr); 171:126: if stdOut.length do -:127: { 0:128: stdOut ~= "\0"; 0:129: puts(stdOut.ptr); -:130: } 171:131: if stdErr.length do -:132: { 1:133: stdErr ~= "\0"; 1:134: puts(stdErr.ptr); -:135: } -:136: 171:137: return r == 0; -:138: -:139: } -:140: else do static assert(0); -:141:} -:142: -:143:/// Archives the objects produced during the session -:144:function linkArchive(): bool -:145:{ -:146: version posix do -:147: { -:148: var Process p; 2:149: p.executable = "/usr/bin/ar"; 2:150: p.redirects = [err, out]; 2:151: p.arguments ~= "rus"; -:152: var s8[+] tempString; 2:153: if session.outputFilename.length do -:154: { 1:155: tempString = session.outputFilename.setExtension(".a\0"); 1:156: p.arguments ~= tempString.ptr; 1:157: tempString.incref; -:158: } -:159: else do -:160: { 1:161: tempString ~= session.objects[0].baseName().setExtension(".a\0"); 1:162: p.arguments ~= tempString.ptr; 1:163: tempString.incref; -:164: } 2:165: foreach var auto o in session.objects do 2:166: p.arguments ~= o.ptr; -:167: var s8[+] stdOut; -:168: var s8[+] stdErr; 2:169: p.execute(); 2:170: var s32 r = p.waitAndRead(&stdOut, &stdErr); -:171: -:172: // ar always puts a useless informational message in stderr if it creates the file 2:173: if r != 0 do -:174: { 0:175: if stdOut.length do -:176: { 0:177: stdOut ~= "\0"; 0:178: puts(stdOut.ptr); -:179: } 0:180: if stdErr.length do -:181: { 0:182: stdErr ~= "\0"; 0:183: puts(stdErr.ptr); -:184: } -:185: } 2:186: return r == 0; -:187: } -:188: else do static assert(0); -:189:} <<<<<< EOF # path=src/styx/backend/llvm.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/backend/llvm.sx -: 1:unit styx.backend.llvm; -: 2: -: 3:@constructor static function initialize() -: 4:{ -: 5: @foreign function LLVMInitializeX86Target(); -: 6: @foreign function LLVMInitializeX86TargetInfo(); -: 7: @foreign function LLVMInitializeX86TargetMC(); -: 8: @foreign function LLVMInitializeX86AsmPrinter(); -: 9: @foreign function LLVMInitializeX86AsmParser(); -: 10: @foreign function LLVMInitializeX86Disassembler(); -: 11: 189: 12: LLVMInitializeX86Target(); 189: 13: LLVMInitializeX86TargetInfo(); 189: 14: LLVMInitializeX86TargetMC(); 189: 15: LLVMInitializeX86AsmPrinter(); 189: 16: LLVMInitializeX86AsmParser(); 189: 17: LLVMInitializeX86Disassembler(); 189: 18:} -: 19: -: 20:@destructor static function finalize() -: 21:{ -: 22: @foreign function LLVMShutdown(); 189: 23: LLVMShutdown(); 189: 24:} -: 25: -: 26:/// Builder for static data or evaluable instructions -: 27:struct constBuilder -: 28:{ -: 29: static function array(LLVMTypeRef elemType; LLVMValueRef[] values): LLVMValueRef -: 30: { -: 31: @foreign function LLVMConstArray(LLVMTypeRef ElementTy; LLVMValueRef* ConstantVals; u32 Length): LLVMValueRef; 1101: 32: return LLVMConstArray(elemType, values.ptr, values.length:u32); -: 33: } -: 34: -: 35: @foreign function LLVMConstInt(LLVMTypeRef IntTy; u64 N; s32 SignExtend): LLVMValueRef; -: 36: alias int = LLVMConstInt; -: 37: -: 38: @foreign function LLVMConstBitCast(LLVMValueRef ConstantVal; LLVMTypeRef ToType): LLVMValueRef; -: 39: alias bitCast = LLVMConstBitCast; -: 40: -: 41: static function gep(LLVMTypeRef ty; LLVMValueRef ptr; LLVMValueRef[] indices): LLVMValueRef -: 42: { -: 43: version LLVM15PLUS do -: 44: { -: 45: @foreign function LLVMConstGEP(LLVMTypeRef ty; LLVMValueRef ConstantVal; LLVMValueRef* ConstantIndices; u32 NumIndices): LLVMValueRef; -: 46: return LLVMConstGEP(ty, ptr, indices.ptr, indices.length:u32); -: 47: } -: 48: else do -: 49: { -: 50: @foreign function LLVMConstGEP2(LLVMTypeRef ty; LLVMValueRef ConstantVal; LLVMValueRef* ConstantIndices; u32 NumIndices): LLVMValueRef; 2323: 51: return LLVMConstGEP2(ty, ptr, indices.ptr, indices.length:u32); -: 52: } -: 53: } -: 54: -: 55: static function namedStruct(LLVMTypeRef structType; LLVMValueRef[] values): LLVMValueRef -: 56: { -: 57: @foreign function LLVMConstNamedStruct(LLVMTypeRef StructTy; LLVMValueRef* ConstantVals; u32 Count): LLVMValueRef; 5052: 58: return LLVMConstNamedStruct(structType, values.ptr, values.length:u32); -: 59: } -: 60: -: 61: static function $structInContext(LLVMContextRef c; LLVMValueRef[] values): LLVMValueRef -: 62: { -: 63: @foreign function LLVMConstStructInContext(LLVMContextRef C; LLVMValueRef* ConstantVals; u32 Count; s32 Packed): LLVMValueRef; 435: 64: return LLVMConstStructInContext(c, values.ptr, values.length:u32, 0); -: 65: } -: 66: -: 67: @foreign function LLVMConstNull(LLVMTypeRef type): LLVMValueRef; -: 68: alias $null = LLVMConstNull; -: 69: alias zeroInit = $null; -: 70: -: 71: @foreign function LLVMConstReal(LLVMTypeRef type; f64 value): LLVMValueRef; -: 72: alias real = LLVMConstReal; -: 73: -: 74: @foreign function LLVMGetUndef(LLVMTypeRef Ty): LLVMValueRef; -: 75: alias undef = LLVMGetUndef; -: 76:} -: 77: -: 78:/// Builder for instructions that require a frame pointer -: 79:/// but also for all LLVM functions that require the same context as the unit. -: 80:struct InstrBuilder -: 81:{ -: 82:protection (private) -: 83: -: 84: @noinit var LLVMBuilderRef b; -: 85: @noinit var LLVMContextRef c; -: 86: -: 87: // instructions names are not allowed to be null because they are used -: 88: // as "Twine". They cause the target 1st char to be always read -: 89: static var s8[] n = "\0"; -: 90: @inline(true) static function safeName(s8* name): s8* -: 91: { 259273: 92: return name ? n.ptr; -: 93: } -: 94: -: 95:protection (public) -: 96: -: 97: @constructor function create(LLVMContextRef ctxt) -: 98: { 283: 99: b = LLVMCreateBuilderInContext(ctxt); 283: 100: c = ctxt; 283: 101: } -: 102: -: 103: @destructor function destroy() -: 104: { 281: 105: LLVMDisposeBuilder(b); 281: 106: } -: 107: -: 108: function add(ValueRef v1; ValueRef v2; s8* name = null): ValueRef -: 109: { -: 110: @foreign function LLVMBuildAdd(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* name): ValueRef; 3155: 111: return LLVMBuildAdd(b, v1, v2, safeName(name)); -: 112: } -: 113: -: 114: function addCase(LLVMValueRef sw; LLVMValueRef onVal; LLVMBasicBlockRef dest) -: 115: { -: 116: @foreign function LLVMAddCase(LLVMValueRef Switch; LLVMValueRef OnVal; LLVMBasicBlockRef Dest); 2294: 117: LLVMAddCase(sw, onVal, dest); 2294: 118: } -: 119: -: 120: function addIncoming(LLVMValueRef phiNode; LLVMValueRef[] values; LLVMBasicBlockRef[] origins) -: 121: { -: 122: @foreign function LLVMAddIncoming(LLVMValueRef PhiNode; LLVMValueRef* IncomingValues; LLVMBasicBlockRef* IncomingBlocks; u32 count); 2659: 123: LLVMAddIncoming(phiNode, values.ptr, origins.ptr, origins.length:u32); 2659: 124: } -: 125: -: 126: function alloca(LLVMTypeRef type; s8* name = null): LLVMValueRef -: 127: { -: 128: @foreign function LLVMBuildAlloca(LLVMBuilderRef builder; LLVMTypeRef Ty; s8* Name): LLVMValueRef; 12313: 129: return LLVMBuildAlloca(b, type, safeName(name)); -: 130: } -: 131: -: 132: function and(ValueRef v1; ValueRef v2; s8* name = null): ValueRef -: 133: { -: 134: @foreign function LLVMBuildAnd(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* name): ValueRef; 321: 135: return LLVMBuildAnd(b, v1, v2, safeName(name)); -: 136: } -: 137: -: 138: function appendBasicBlock(LLVMValueRef func; s8* name = null): LLVMBasicBlockRef -: 139: { -: 140: @foreign function LLVMAppendBasicBlockInContext(LLVMContextRef c; LLVMValueRef f; s8* name): LLVMBasicBlockRef; 57583: 141: return LLVMAppendBasicBlockInContext(c, func, safeName(name)); -: 142: } -: 143: -: 144: function bitCast(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 145: { -: 146: @foreign function LLVMBuildBitCast(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 4132: 147: return LLVMBuildBitCast(b, value, toType, safeName(name)); -: 148: } -: 149: -: 150: function br(LLVMBasicBlockRef dest): LLVMValueRef -: 151: { -: 152: @foreign function LLVMBuildBr(LLVMBuilderRef builder; LLVMBasicBlockRef dest): LLVMValueRef; 16431: 153: return LLVMBuildBr(b, dest); -: 154: } -: 155: -: 156: function call(LLVMTypeRef ty; LLVMValueRef func; LLVMValueRef[] args; s8* name = null): LLVMValueRef -: 157: { -: 158: version LLVM15PLUS do -: 159: { -: 160: @foreign function LLVMBuildCall(LLVMBuilderRef b; LLVMTypeRef ty; LLVMValueRef Fn; LLVMValueRef* Args; u32 NumArgs; s8* Name): LLVMValueRef; -: 161: return LLVMBuildCall(b, ty, func, args.ptr, args.length:u32, safeName(name)); -: 162: } -: 163: else do -: 164: { -: 165: @foreign function LLVMBuildCall2(LLVMBuilderRef b; LLVMTypeRef ty; LLVMValueRef Fn; LLVMValueRef* Args; u32 NumArgs; s8* Name): LLVMValueRef; 64943: 166: return LLVMBuildCall2(b, ty, func, args.ptr, args.length:u32, safeName(name)); -: 167: } -: 168: } -: 169: -: 170: function condBr(LLVMValueRef condition; LLVMBasicBlockRef thenBr; LLVMBasicBlockRef elseBr): LLVMValueRef -: 171: { -: 172: @foreign function LLVMBuildCondBr(LLVMBuilderRef b; LLVMValueRef If; LLVMBasicBlockRef Then; LLVMBasicBlockRef Else): LLVMValueRef; 22418: 173: return LLVMBuildCondBr(b, condition, thenBr, elseBr); -: 174: } -: 175: -: 176: @foreign function LLVMDeleteBasicBlock(LLVMBasicBlockRef BB); -: 177: alias deleteBasicBlock = LLVMDeleteBasicBlock; -: 178: -: 179: function extractValue(LLVMValueRef agg; usize index; s8* name = null): LLVMValueRef -: 180: { -: 181: @foreign function LLVMBuildExtractValue(LLVMBuilderRef b; LLVMValueRef AggVal; u32 Index; const s8* Name): LLVMValueRef; 44: 182: return LLVMBuildExtractValue(b, agg, index:u32, safeName(name)); -: 183: } -: 184: -: 185: function fadd(ValueRef v1; ValueRef v2; s8* name = null): ValueRef -: 186: { -: 187: @foreign function LLVMBuildFAdd(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* name): ValueRef; 4: 188: return LLVMBuildFAdd(b, v1, v2, safeName(name)); -: 189: } -: 190: -: 191: function fcmp(LLVMRealPredicate pred; ValueRef v1; ValueRef v2; s8* name = null): LLVMValueRef -: 192: { -: 193: @foreign function LLVMBuildFCmp(LLVMBuilderRef b; LLVMRealPredicate Op; LLVMValueRef LHS; LLVMValueRef RHS; s8* Name): LLVMValueRef; 33: 194: return LLVMBuildFCmp(b, pred, v1, v2, safeName(name)); -: 195: } -: 196: -: 197: function fdiv(ValueRef v1; ValueRef v2; s8* name = null): ValueRef -: 198: { -: 199: @foreign function LLVMBuildFDiv(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* Name): ValueRef; 1: 200: return LLVMBuildFDiv(b, v1, v2, safeName(name)); -: 201: } -: 202: -: 203: function fmul(ValueRef v1; ValueRef v2; s8* name = null): ValueRef -: 204: { -: 205: @foreign function LLVMBuildFMul(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* Name): ValueRef; 1: 206: return LLVMBuildFMul(b, v1, v2, safeName(name)); -: 207: } -: 208: -: 209: function fneg(LLVMValueRef value; s8* name = null): LLVMValueRef -: 210: { -: 211: @foreign function LLVMBuildFNeg(LLVMBuilderRef builder; LLVMValueRef V; s8* Name): LLVMValueRef; 1: 212: return LLVMBuildFNeg(b, value, safeName(name)); -: 213: } -: 214: -: 215: function fpExt(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 216: { -: 217: @foreign function LLVMBuildFPExt(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 5: 218: return LLVMBuildFPExt(b, value, toType, safeName(name)); -: 219: } -: 220: -: 221: function fpTrunc(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 222: { -: 223: @foreign function LLVMBuildFPTrunc(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 4: 224: return LLVMBuildFPTrunc(b, value, toType, safeName(name)); -: 225: } -: 226: -: 227: function fpToSi(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 228: { -: 229: @foreign function LLVMBuildFPToSI(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 1: 230: return LLVMBuildFPToSI(b, value, toType, safeName(name)); -: 231: } -: 232: -: 233: function fpToUi(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 234: { -: 235: @foreign function LLVMBuildFPToUI(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 5: 236: return LLVMBuildFPToUI(b, value, toType, safeName(name)); -: 237: } -: 238: -: 239: function frem(ValueRef v1; ValueRef v2; s8* name = null): ValueRef -: 240: { -: 241: @foreign function LLVMBuildFRem(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* Name): ValueRef; 1: 242: return LLVMBuildFRem(b, v1, v2, safeName(name)); -: 243: } -: 244: -: 245: function fsub(ValueRef v1; ValueRef v2; s8* name = null): ValueRef -: 246: { -: 247: @foreign function LLVMBuildFSub(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* Name): ValueRef; 3: 248: return LLVMBuildFSub(b, v1, v2, safeName(name)); -: 249: } -: 250: -: 251: function free(LLVMValueRef ptr): LLVMValueRef -: 252: { -: 253: @foreign function LLVMBuildFree(LLVMBuilderRef builder; LLVMValueRef PointerVal): LLVMValueRef; 241: 254: return LLVMBuildFree(b, ptr); -: 255: } -: 256: -: 257: function gep(LLVMTypeRef ty; LLVMValueRef ptr; LLVMValueRef[] indices; s8* name = null): LLVMValueRef -: 258: { -: 259: version LLVM15PLUS do -: 260: { -: 261: @foreign function LLVMBuildGEP(LLVMBuilderRef B;LLVMTypeRef Ty; LLVMValueRef Pointer; -: 262: LLVMValueRef* Indices; u32 NumIndices; s8* Name): LLVMValueRef; -: 263: return LLVMBuildGEP(b, ty, ptr, indices.ptr, indices.length:u32, safeName(name)); -: 264: } -: 265: else do -: 266: { -: 267: @foreign function LLVMBuildGEP2(LLVMBuilderRef B;LLVMTypeRef Ty; LLVMValueRef Pointer; -: 268: LLVMValueRef* Indices; u32 NumIndices; s8* Name): LLVMValueRef; 6741: 269: return LLVMBuildGEP2(b, ty, ptr, indices.ptr, indices.length:u32, safeName(name)); -: 270: } -: 271: } -: 272: -: 273: @foreign function LLVMGetBasicBlockTerminator (LLVMBasicBlockRef BB): LLVMValueRef; -: 274: alias getBasicBlockTerminator = LLVMGetBasicBlockTerminator; -: 275: -: 276: function globalStringPtr(s8[] text; s8* name = null): LLVMValueRef -: 277: { -: 278: @foreign function LLVMBuildGlobalStringPtr(LLVMBuilderRef B; s8* Str; s8* Name): LLVMValueRef; 2264: 279: return LLVMBuildGlobalStringPtr(b, text.ptr, safeName(name)); -: 280: } -: 281: -: 282: function icmp(LLVMIntPredicate pred; ValueRef v1; ValueRef v2; s8* name = null): LLVMValueRef -: 283: { -: 284: @foreign function LLVMBuildICmp (LLVMBuilderRef b; LLVMIntPredicate Op; LLVMValueRef LHS; LLVMValueRef RHS; s8* Name): LLVMValueRef; 20677: 285: return LLVMBuildICmp(b, pred, v1, v2, safeName(name)); -: 286: } -: 287: -: 288: function intToPtr(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 289: { -: 290: @foreign function LLVMBuildIntToPtr(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 4: 291: return LLVMBuildIntToPtr(b, value, toType, safeName(name)); -: 292: } -: 293: -: 294: function load(LLVMTypeRef ty; LLVMValueRef ptr; s8* name = null): LLVMValueRef -: 295: { -: 296: version LLVM15PLUS do -: 297: { -: 298: @foreign function LLVMBuildLoad(LLVMBuilderRef b; LLVMTypeRef Ty; LLVMValueRef PointerVal; s8* Name): LLVMValueRef; -: 299: return LLVMBuildLoad(b, ty, ptr, safeName(name)); -: 300: } -: 301: else do -: 302: { -: 303: @foreign function LLVMBuildLoad2(LLVMBuilderRef b; LLVMTypeRef Ty; LLVMValueRef PointerVal; s8* Name): LLVMValueRef; 47064: 304: return LLVMBuildLoad2(b, ty, ptr, safeName(name)); -: 305: } -: 306: } -: 307: -: 308: function malloc(LLVMTypeRef type; s8* name = null): LLVMValueRef -: 309: { -: 310: @foreign function LLVMBuildMalloc(LLVMBuilderRef builder; LLVMTypeRef Ty; s8* Name): LLVMValueRef; 684: 311: return LLVMBuildMalloc(b, type, safeName(name)); -: 312: } -: 313: -: 314: function memmove(LLVMValueRef dest; u32 destAlign; LLVMValueRef src; u32 srcAlign; LLVMValueRef numBytes): LLVMValueRef -: 315: { -: 316: @foreign function LLVMBuildMemMove(LLVMBuilderRef B; LLVMValueRef Dst; u32 DstAlign; LLVMValueRef Src; u32 SrcAlign; LLVMValueRef Size): LLVMValueRef; 146: 317: return LLVMBuildMemMove(b, dest, destAlign, src, srcAlign, numBytes); -: 318: } -: 319: -: 320: function memset(LLVMValueRef Ptr; LLVMValueRef Val; LLVMValueRef Len; u32 Align): LLVMValueRef -: 321: { -: 322: @foreign function LLVMBuildMemSet(LLVMBuilderRef B; LLVMValueRef Ptr; LLVMValueRef Val; LLVMValueRef Len; u32 Align): LLVMValueRef; 1: 323: return LLVMBuildMemSet(b, Ptr, Val, Len, Align); -: 324: } -: 325: -: 326: function metadataAsValue(LLVMMetadataRef m): LLVMValueRef -: 327: { -: 328: @foreign function LLVMMetadataAsValue(LLVMContextRef C; LLVMMetadataRef MD): LLVMValueRef ; 21627: 329: return LLVMMetadataAsValue(c, m); -: 330: } -: 331: -: 332: function mul(LLVMValueRef v1; LLVMValueRef v2; s8* name = null): ValueRef -: 333: { -: 334: @foreign function LLVMBuildMul(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* Name): ValueRef; 2278: 335: return LLVMBuildMul(b, v1, v2, safeName(name)); -: 336: } -: 337: -: 338: function neg(LLVMValueRef value; s8* name = null): LLVMValueRef -: 339: { -: 340: @foreign function LLVMBuildNeg(LLVMBuilderRef builder; LLVMValueRef V; s8* Name): LLVMValueRef; 61: 341: return LLVMBuildNeg(b, value, safeName(name)); -: 342: } -: 343: -: 344: function not(LLVMValueRef value; s8* name = null): LLVMValueRef -: 345: { -: 346: @foreign function LLVMBuildNot(LLVMBuilderRef builder; LLVMValueRef V; s8* Name): LLVMValueRef; 558: 347: return LLVMBuildNot(b, value, safeName(name)); -: 348: } -: 349: -: 350: function or(ValueRef v1; ValueRef v2; s8* name = null): ValueRef -: 351: { -: 352: @foreign function LLVMBuildOr(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* Name): ValueRef; 169: 353: return LLVMBuildOr(b, v1, v2, safeName(name)); -: 354: } -: 355: -: 356: function phi(LLVMTypeRef type; s8* name = null): LLVMValueRef -: 357: { -: 358: @foreign function LLVMBuildPhi(LLVMBuilderRef builder; LLVMTypeRef Ty; s8* Name): LLVMValueRef; 2659: 359: return LLVMBuildPhi(b, type, safeName(name)); -: 360: } -: 361: -: 362: function pointerCast(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 363: { -: 364: @foreign function LLVMBuildPointerCast(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 3: 365: return LLVMBuildPointerCast(b, value, toType, safeName(name)); -: 366: } -: 367: -: 368: function positionAtEnd(LLVMBasicBlockRef br) -: 369: { -: 370: @foreign function LLVMPositionBuilderAtEnd(LLVMBuilderRef Builder; LLVMBasicBlockRef Block); 60815: 371: LLVMPositionBuilderAtEnd(b, br); 60815: 372: } -: 373: -: 374: function ptrDiff(LLVMTypeRef ty; LLVMValueRef v1; LLVMValueRef v2; s8* name = null): LLVMValueRef -: 375: { -: 376: version LLVM15PLUS do -: 377: { -: 378: @foreign function LLVMBuildPtrDiff(LLVMBuilderRef builder; LLVMTypeRef ty; LLVMValueRef Val1; LLVMValueRef Val2; s8* Name): LLVMValueRef; -: 379: return LLVMBuildPtrDiff(b, ty, v1, v2, safeName(name)); -: 380: } -: 381: else do -: 382: { -: 383: @foreign function LLVMBuildPtrDiff2(LLVMBuilderRef builder; LLVMTypeRef ty; LLVMValueRef Val1; LLVMValueRef Val2; s8* Name): LLVMValueRef; 3: 384: return LLVMBuildPtrDiff2(b, ty, v1, v2, safeName(name)); -: 385: } -: 386: } -: 387: -: 388: function ptrToInt(LLVMValueRef v; LLVMTypeRef t; s8* name = null): LLVMValueRef -: 389: { -: 390: @foreign function LLVMBuildPtrToInt(LLVMBuilderRef builder; LLVMValueRef Val; LLVMTypeRef DestTy; s8* Name): LLVMValueRef; 1671: 391: return LLVMBuildPtrToInt(b, v, t, safeName(name)); -: 392: } -: 393: -: 394: function ret(LLVMValueRef value): LLVMValueRef -: 395: { -: 396: @foreign function LLVMBuildRet(LLVMBuilderRef builder; LLVMValueRef V): LLVMValueRef; 2921: 397: return LLVMBuildRet(b, value); -: 398: } -: 399: -: 400: function retVoid(): LLVMValueRef -: 401: { -: 402: @foreign function LLVMBuildRetVoid(LLVMBuilderRef builder): LLVMValueRef; 2557: 403: return LLVMBuildRetVoid(b); -: 404: } -: 405: -: 406: function sdiv(ValueRef v1; ValueRef v2; s8* name = null): ValueRef -: 407: { -: 408: @foreign function LLVMBuildSDiv(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* Name): ValueRef; 3: 409: return LLVMBuildSDiv(b, v1, v2, safeName(name)); -: 410: } -: 411: -: 412: function select(LLVMValueRef condition; LLVMValueRef thenValue; LLVMValueRef elseValue; s8* name = null): LLVMValueRef -: 413: { -: 414: @foreign function LLVMBuildSelect(LLVMBuilderRef builder; LLVMValueRef If; LLVMValueRef Then; LLVMValueRef Else; s8* Name): LLVMValueRef; 136: 415: return LLVMBuildSelect(b, condition, thenValue, elseValue, safeName(name)); -: 416: } -: 417: -: 418: function sext(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 419: { -: 420: @foreign function LLVMBuildSExt(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 200: 421: return LLVMBuildSExt(b, value, toType, safeName(name)); -: 422: } -: 423: -: 424: function siToFp(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 425: { -: 426: @foreign function LLVMBuildSIToFP(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 1: 427: return LLVMBuildSIToFP(b, value, toType, safeName(name)); -: 428: } -: 429: -: 430: function shl(LLVMValueRef value; LLVMValueRef amount; s8* name = null): LLVMValueRef -: 431: { -: 432: @foreign function LLVMBuildShl(LLVMBuilderRef builder; LLVMValueRef LHS; LLVMValueRef RHS; s8* Name): LLVMValueRef; 392: 433: return LLVMBuildShl(b, value, amount, safeName(name)); -: 434: } -: 435: -: 436: function shr(LLVMValueRef value; LLVMValueRef amount; s8* name = null): LLVMValueRef -: 437: { -: 438: @foreign function LLVMBuildLShr(LLVMBuilderRef builder; LLVMValueRef LHS; LLVMValueRef RHS; s8* Name): LLVMValueRef; 232: 439: return LLVMBuildLShr(b, value, amount, safeName(name)); -: 440: } -: 441: -: 442: function srem(ValueRef v1; ValueRef v2; s8* name = null): ValueRef -: 443: { -: 444: @foreign function LLVMBuildSRem(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* Name): ValueRef; 4: 445: return LLVMBuildSRem(b, v1, v2, safeName(name)); -: 446: } -: 447: -: 448: function store(LLVMValueRef val; LLVMValueRef ptr): LLVMValueRef -: 449: { -: 450: @foreign function LLVMBuildStore(LLVMBuilderRef builder; LLVMValueRef Val; LLVMValueRef Ptr): LLVMValueRef; 27937: 451: return LLVMBuildStore(b, val, ptr); -: 452: } -: 453: -: 454: function string(s8[] value): LLVMValueRef -: 455: { -: 456: @foreign function LLVMConstStringInContext(LLVMContextRef C; s8* Str; u32 Length; s32 DontNullTerminate): LLVMValueRef; 1541: 457: return LLVMConstStringInContext(c, value.ptr, value.length:u32, false); -: 458: } -: 459: -: 460: function structGep(LLVMTypeRef ty; LLVMValueRef structPtr; usize memberIndex; s8* name = null): LLVMValueRef -: 461: { -: 462: version LLVM15PLUS do -: 463: { -: 464: @foreign function LLVMBuildStructGEP(LLVMBuilderRef B; LLVMTypeRef Ty; LLVMValueRef Pointer; u32 Idx; s8* Name): LLVMValueRef; -: 465: return LLVMBuildStructGEP(b, ty, structPtr, memberIndex:u32, safeName(name)); -: 466: } -: 467: else do -: 468: { -: 469: @foreign function LLVMBuildStructGEP2(LLVMBuilderRef B; LLVMTypeRef Ty; LLVMValueRef Pointer; u32 Idx; s8* Name): LLVMValueRef; 19862: 470: return LLVMBuildStructGEP2(b, ty, structPtr, memberIndex:u32, safeName(name)); -: 471: } -: 472: } -: 473: -: 474: function sub(LLVMValueRef v1; LLVMValueRef v2; s8* name = null): LLVMValueRef -: 475: { -: 476: @foreign function LLVMBuildSub(LLVMBuilderRef builder; LLVMValueRef v1; LLVMValueRef v2; s8* name): ValueRef; 2488: 477: return LLVMBuildSub(b, v1, v2, safeName(name)); -: 478: } -: 479: -: 480: function $switch(LLVMValueRef value; LLVMBasicBlockRef elseBlock; usize numCases): LLVMValueRef -: 481: { -: 482: @foreign function LLVMBuildSwitch(LLVMBuilderRef builder; LLVMValueRef V; LLVMBasicBlockRef Else; u32 NumCases): LLVMValueRef; 256: 483: return LLVMBuildSwitch(b, value, elseBlock, numCases:u32); -: 484: } -: 485: -: 486: function trunc(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 487: { -: 488: @foreign function LLVMBuildTrunc(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; const s8* name): LLVMValueRef; 1675: 489: return LLVMBuildTrunc(b, value, toType, safeName(name)); -: 490: } -: 491: -: 492: function truncOrBitCast(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 493: { -: 494: @foreign function LLVMBuildTruncOrBitCast(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 224: 495: return LLVMBuildTruncOrBitCast(b, value, toType, safeName(name)); -: 496: } -: 497: -: 498: function uiToFp(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 499: { -: 500: @foreign function LLVMBuildUIToFP(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 15: 501: return LLVMBuildUIToFP(b, value, toType, safeName(name)); -: 502: } -: 503: -: 504: function udiv(LLVMValueRef v1; LLVMValueRef v2; s8* name = null): LLVMValueRef -: 505: { -: 506: @foreign function LLVMBuildUDiv(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* Name): ValueRef; 318: 507: return LLVMBuildUDiv(b, v1, v2, safeName(name)); -: 508: } -: 509: -: 510: function unreachable() -: 511: { -: 512: @foreign function LLVMBuildUnreachable(LLVMBuilderRef builder): LLVMValueRef; 12977: 513: LLVMBuildUnreachable(b); 12977: 514: } -: 515: -: 516: function urem(LLVMValueRef v1; LLVMValueRef v2; s8* name = null): LLVMValueRef -: 517: { -: 518: @foreign function LLVMBuildURem(LLVMBuilderRef builder; ValueRef v1; ValueRef v2; s8* Name): ValueRef; 56: 519: return LLVMBuildURem(b, v1, v2, safeName(name)); -: 520: } -: 521: -: 522: function xor(LLVMValueRef v1; LLVMValueRef v2; s8* name = null): LLVMValueRef -: 523: { -: 524: @foreign function LLVMBuildXor(LLVMBuilderRef builder; LLVMValueRef v1; LLVMValueRef v2; s8* name): LLVMValueRef; 76: 525: return LLVMBuildXor(b, v1, v2, safeName(name)); -: 526: } -: 527: -: 528: function zext(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 529: { -: 530: @foreign function LLVMBuildZExt(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 3921: 531: return LLVMBuildZExt(b, value, toType, safeName(name)); -: 532: } -: 533: -: 534: function zextOrBitcast(LLVMValueRef value; LLVMTypeRef toType; s8* name = null): LLVMValueRef -: 535: { -: 536: @foreign function LLVMBuildZExtOrBitCast(LLVMBuilderRef builder; LLVMValueRef v; LLVMTypeRef t; s8* name): LLVMValueRef; 2284: 537: return LLVMBuildZExtOrBitCast(b, value, toType, safeName(name)); -: 538: } -: 539:} -: 540: -: 541:/// Builder for the optimizers passes -: 542:struct PassManagerBuilder -: 543:{ -: 544: @noinit var LLVMPassManagerBuilderRef builder; -: 545: -: 546: @constructor function create() -: 547: { -: 548: @foreign function LLVMPassManagerBuilderCreate(): LLVMPassManagerBuilderRef; 1: 549: builder = LLVMPassManagerBuilderCreate(); 1: 550: } -: 551: -: 552: @destructor function destroy() -: 553: { -: 554: @foreign function LLVMPassManagerBuilderDispose(LLVMPassManagerBuilderRef builder); 1: 555: LLVMPassManagerBuilderDispose(builder); 1: 556: } -: 557: -: 558: // set level, 0, 1, 2, or 3 -: 559: function setOptLevel(s32 value) -: 560: { -: 561: @foreign function LLVMPassManagerBuilderSetOptLevel(LLVMPassManagerBuilderRef builder; s32 value); 1: 562: LLVMPassManagerBuilderSetOptLevel(builder, value); 1: 563: } -: 564: -: 565: // -: 566: function setSizeLevel(s32 value) -: 567: { -: 568: @foreign function LLVMPassManagerBuilderSetSizeLevel(LLVMPassManagerBuilderRef builder; s32 value); 1: 569: LLVMPassManagerBuilderSetSizeLevel(builder, value); 1: 570: } -: 571: -: 572: // used to decide with the attribute "inlinehint" -: 573: function setInlineThresh(s32 value) -: 574: { -: 575: @foreign function LLVMPassManagerBuilderUseInlinerWithThreshold(LLVMPassManagerBuilderRef builder; s32 value); 1: 576: LLVMPassManagerBuilderUseInlinerWithThreshold(builder, value); 1: 577: } -: 578: -: 579: // add the default set of passes for functions, e.g the one designed for C/C++ -: 580: function addDefaultFunctionPasses(PassManager* pm) -: 581: { -: 582: @foreign function LLVMPassManagerBuilderPopulateFunctionPassManager(LLVMPassManagerBuilderRef b; LLVMPassManagerRef pm); 1: 583: LLVMPassManagerBuilderPopulateFunctionPassManager(builder, pm.funPm); 1: 584: } -: 585: -: 586: // add the default set of passes for a module, e.g the one designed for C/C++ -: 587: function addDefaultModulePasses(PassManager* pm) -: 588: { -: 589: @foreign function LLVMPassManagerBuilderPopulateModulePassManager(LLVMPassManagerBuilderRef b; LLVMPassManagerRef pm); 1: 590: LLVMPassManagerBuilderPopulateModulePassManager(builder, pm.modPm); 1: 591: } -: 592:} -: 593: -: 594:/// Wraps the module and function optimizers passes -: 595:struct PassManager -: 596:{ -: 597: @noinit var LLVMPassManagerRef funPm; -: 598: @noinit var LLVMPassManagerRef modPm; -: 599: @noinit var LLVMModuleRef mod; -: 600: -: 601: @constructor function create(LLVMModuleRef module) -: 602: { -: 603: @foreign function LLVMCreateFunctionPassManagerForModule(LLVMModuleRef module): LLVMPassManagerRef; -: 604: @foreign function LLVMInitializeFunctionPassManager(LLVMPassManagerRef m): s32; -: 605: @foreign function LLVMCreatePassManager(): LLVMPassManagerRef; -: 606: 1: 607: funPm = LLVMCreateFunctionPassManagerForModule(module); 1: 608: modPm = LLVMCreatePassManager(); 1: 609: mod = module; -: 610: 1: 611: LLVMInitializeFunctionPassManager(funPm); 1: 612: } -: 613: -: 614: @destructor function destroy() -: 615: { -: 616: @foreign function LLVMDisposePassManager(LLVMPassManagerRef pm); -: 617: 1: 618: LLVMDisposePassManager(funPm); 1: 619: LLVMDisposePassManager(modPm); 1: 620: } -: 621: -: 622: /// Optimize all the functions in the module passed in the constructor -: 623: function runFunctions() -: 624: { -: 625: @foreign function LLVMGetFirstFunction(LLVMModuleRef m): LLVMValueRef; -: 626: @foreign function LLVMGetNextFunction(LLVMValueRef f): LLVMValueRef; -: 627: @foreign function LLVMRunFunctionPassManager(LLVMPassManagerRef m; LLVMValueRef f): s32; -: 628: @foreign function LLVMFinalizeFunctionPassManager(LLVMPassManagerRef m): s32; -: 629: 1: 630: var LLVMValueRef func = LLVMGetFirstFunction(mod); 1: 631: while func do -: 632: { 4: 633: LLVMRunFunctionPassManager(funPm, func); 4: 634: func = LLVMGetNextFunction(func); -: 635: } 1: 636: LLVMFinalizeFunctionPassManager(funPm); 1: 637: } -: 638: -: 639: /// Optimize the module passed in the constructor -: 640: function runModule() -: 641: { -: 642: @foreign function LLVMRunPassManager(LLVMPassManagerRef pm; LLVMModuleRef m): s32; 1: 643: LLVMRunPassManager(modPm, mod); 1: 644: } -: 645:} -: 646: -: 647:/// Builder for the DWARF debug information -: 648:struct DIBuilder -: 649:{ -: 650:protection(private) -: 651: -: 652: @noinit var LLVMContextRef c; -: 653: @noinit var LLVMDIBuilderRef b; -: 654: @noinit var LLVMModuleRef m; -: 655: @noinit var LLVMMetadataRef f; -: 656: -: 657:protection(public) -: 658: -: 659: @constructor function create(LLVMContextRef c; LLVMModuleRef m) -: 660: { -: 661: @foreign function LLVMCreateDIBuilder(LLVMModuleRef M): LLVMDIBuilderRef; 47: 662: this.b = LLVMCreateDIBuilder(m); 47: 663: this.c = c; 47: 664: this.m = m; 47: 665: } -: 666: -: 667: @destructor function destroy() -: 668: { -: 669: @foreign function LLVMDisposeDIBuilder(LLVMDIBuilderRef Builder); 47: 670: LLVMDisposeDIBuilder(b); 47: 671: } -: 672: -: 673: function finalize() -: 674: { -: 675: @foreign function LLVMDIBuilderFinalize(LLVMDIBuilderRef Builder); 47: 676: LLVMDIBuilderFinalize(b); 47: 677: } -: 678: -: 679: function createArrayType(u32 bitSize; u32 bitAlign; LLVMMetadataRef ty): LLVMMetadataRef -: 680: { -: 681: @foreign function LLVMDIBuilderCreateArrayType(LLVMDIBuilderRef Builder; u64 Size; u32 AlignInBits; LLVMMetadataRef Ty; LLVMMetadataRef* Subscripts; u32 NumSubscripts): LLVMMetadataRef; 4463: 682: return LLVMDIBuilderCreateArrayType(b, bitSize, bitAlign, ty, null , 0); -: 683: } -: 684: -: 685: function createBasicType(s8[] name; u32 bitSz; DWARF_ENCODING enc; LLVMDIFlags flags): LLVMMetadataRef -: 686: { -: 687: @foreign function LLVMDIBuilderCreateBasicType(LLVMDIBuilderRef Builder; const s8* Name; usize NameLen; u64 SizeInBits; DWARF_ENCODING Encoding; LLVMDIFlags Flags): LLVMMetadataRef; 517: 688: return LLVMDIBuilderCreateBasicType(b, name.ptr, name.length, bitSz, enc, flags); -: 689: } -: 690: -: 691: function createClassType(LLVMMetadataRef scope; s8[] name; u32 line; u32 bitSize; u32 bitAlign; LLVMDIFlags flags; LLVMMetadataRef baseTypeDi; LLVMMetadataRef[] members): LLVMMetadataRef -: 692: { -: 693: @foreign function LLVMDIBuilderCreateClassType( -: 694: LLVMDIBuilderRef Builder; -: 695: LLVMMetadataRef Scope; -: 696: const s8* Name; usize NameLen; -: 697: LLVMMetadataRef File; -: 698: u32 LineNumber; -: 699: u64 SizeInBits; -: 700: u32 AlignInBits; -: 701: u64 OffsetInBits; -: 702: LLVMDIFlags Flags; -: 703: LLVMMetadataRef DerivedFrom; -: 704: LLVMMetadataRef* Elements; u32 NumElements; -: 705: LLVMMetadataRef VTableHolder; -: 706: LLVMMetadataRef TemplateParamsNode; -: 707: const s8* UniqueIdentifier; usize UniqueIdentifierLen): LLVMMetadataRef; 4305: 708: return LLVMDIBuilderCreateClassType(b, scope, name.ptr, name.length, f, line, bitSize, bitAlign, 0, flags, baseTypeDi, members.ptr, members.length:u32, null, null, name.ptr, name.length); -: 709: } -: 710: -: 711: function createCompileUnit(s8[] producer; bool isOptimized): LLVMMetadataRef -: 712: { -: 713: @foreign function LLVMDIBuilderCreateCompileUnit ( -: 714: LLVMDIBuilderRef Builder; -: 715: LLVMDWARFSourceLanguage Lang; -: 716: LLVMMetadataRef FileRef; -: 717: const s8* Producer; usize ProducerLen; -: 718: s32 isOptimized; -: 719: const s8* Flags; usize FlagsLen; -: 720: u32 RuntimeVer; -: 721: const s8* SplitName; usize SplitNameLen; -: 722: LLVMDWARFEmissionKind Kind; -: 723: u32 DWOId; -: 724: s32 SplitDebugInlining; -: 725: s32 DebugInfoForProfiling; -: 726: const s8* SysRoot; usize SysRootLen; -: 727: const s8* SDK; usize SDKLen): LLVMMetadataRef; -: 728: 47: 729: return LLVMDIBuilderCreateCompileUnit(b, LLVMDWARFSourceLanguage.C, f, producer.ptr, producer.length, isOptimized, null, 0, 0, "temp.txt", 8, LLVMDWARFEmissionKind.Full, 0, false, false, null, 0, null, 0); -: 730: -: 731: } -: 732: -: 733: function createDebugLocation(u32 line; u32 col; LLVMMetadataRef scope; LLVMMetadataRef inlinedAt = null): LLVMMetadataRef -: 734: { -: 735: @foreign function LLVMDIBuilderCreateDebugLocation(LLVMContextRef Ctx; u32 Line; u32 Column; LLVMMetadataRef Scope; LLVMMetadataRef InlinedAt): LLVMMetadataRef; 43068: 736: return LLVMDIBuilderCreateDebugLocation(c, line, col, scope, inlinedAt); -: 737: } -: 738: -: 739: function createEnumMember(s8[] name; u64 value; bool isSigned): LLVMMetadataRef -: 740: { -: 741: @foreign function LLVMDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder; const s8* Name; usize NameLen; u64 Value; s32 IsUnsigned): LLVMMetadataRef; 9543: 742: return LLVMDIBuilderCreateEnumerator(b, name.ptr, name.length, value, !isSigned); -: 743: } -: 744: -: 745: function createEnumerationType(LLVMMetadataRef scope; s8[] name; u32 line; u32 bitSize; u32 bitAlign; LLVMMetadataRef[] members; LLVMMetadataRef baseTypeDi): LLVMMetadataRef -: 746: { -: 747: @foreign function LLVMDIBuilderCreateEnumerationType( -: 748: LLVMDIBuilderRef Builder; -: 749: LLVMMetadataRef Scope; -: 750: const s8* Name; usize NameLen; -: 751: LLVMMetadataRef File; -: 752: u32 LineNumber; -: 753: u64 SizeInBits; -: 754: u32 AlignInBits; -: 755: LLVMMetadataRef* Elements; u32 NumElements; -: 756: LLVMMetadataRef ClassTy): LLVMMetadataRef; 341: 757: return LLVMDIBuilderCreateEnumerationType(b, scope, name.ptr, name.length, f, line, bitSize, bitAlign, members.ptr, members.length:u32, baseTypeDi); -: 758: } -: 759: -: 760: function createDummyExpression(): LLVMMetadataRef -: 761: { -: 762: @foreign function LLVMDIBuilderCreateExpression(LLVMDIBuilderRef Builder; u64* Addr; usize Length): LLVMMetadataRef; 7919: 763: return LLVMDIBuilderCreateExpression(b, null, 0); -: 764: } -: 765: -: 766: function createFile(s8[] filename; s8[] dir): LLVMMetadataRef -: 767: { -: 768: @foreign function LLVMDIBuilderCreateFile(LLVMDIBuilderRef Builder; s8* Filename; usize FilenameLen; s8* Directory; usize DirectoryLen): LLVMMetadataRef; 47: 769: return f = LLVMDIBuilderCreateFile(b, filename.ptr, filename.length, dir.ptr, dir.length); -: 770: } -: 771: -: 772: function createFunction(s8[] name; u32 line; LLVMMetadataRef funcTypeDi; -: 773: bool isLocalToUnit; bool isDefinition; bool isOptimized; LLVMDIFlags flags; LLVMValueRef funcIr): LLVMMetadataRef -: 774: { -: 775: @foreign function LLVMSetSubprogram(LLVMValueRef Func; LLVMMetadataRef SP); -: 776: @foreign function LLVMDIBuilderCreateFunction( -: 777: LLVMDIBuilderRef Builder; -: 778: LLVMMetadataRef Scope; -: 779: const s8* Name; usize NameLen; -: 780: const s8* LinkageName; usize LinkageNameLen; -: 781: LLVMMetadataRef File; -: 782: u32 LineNo; -: 783: LLVMMetadataRef Ty; -: 784: s32 IsLocalToUnit; -: 785: s32 IsDefinition; -: 786: u32 ScopeLine; -: 787: LLVMDIFlags Flags; -: 788: s32 IsOptimized): LLVMMetadataRef; 2121: 789: var auto r = LLVMDIBuilderCreateFunction(b, f, name.ptr, name.length, name.ptr, name.length, f, -: 790: line, funcTypeDi, isLocalToUnit, isDefinition, line, flags, isOptimized); 2121: 791: LLVMSetSubprogram(funcIr, r); 2121: 792: return r; -: 793: } -: 794: -: 795: function createGlobalVariableExpression(LLVMMetadataRef scope; s8[] name; s8[] linkage; u32 line; LLVMMetadataRef typeDi; -: 796: bool isLocalToUnit; u32 bitAlign): LLVMMetadataRef -: 797: { -: 798: @foreign function LLVMDIBuilderCreateGlobalVariableExpression ( -: 799: LLVMDIBuilderRef Builder; -: 800: LLVMMetadataRef Scope; -: 801: const s8* Name; usize NameLen; -: 802: const s8* Linkage; usize LinkLen; -: 803: LLVMMetadataRef File; -: 804: u32 LineNo; -: 805: LLVMMetadataRef Ty; -: 806: s32 isLocalToUnit; -: 807: LLVMMetadataRef Expr; -: 808: LLVMMetadataRef Decl; -: 809: u32 AlignInBits): LLVMMetadataRef; 710: 810: return LLVMDIBuilderCreateGlobalVariableExpression(b, scope, name.ptr, name.length, linkage.ptr, linkage.length, f, line, -: 811: typeDi, isLocalToUnit, createDummyExpression(), null, bitAlign); -: 812: } -: 813: -: 814: function createInheritance(LLVMMetadataRef inheritedTypeDi): LLVMMetadataRef -: 815: { -: 816: @foreign function LLVMDIBuilderCreateInheritance( -: 817: LLVMDIBuilderRef Builder; -: 818: LLVMMetadataRef Ty; -: 819: LLVMMetadataRef BaseTy; -: 820: u64 BaseOffset; -: 821: u32 VBPtrOffset; -: 822: LLVMDIFlags Flags): LLVMMetadataRef; 3976: 823: return LLVMDIBuilderCreateInheritance(b, null, inheritedTypeDi, getTypeOffset(inheritedTypeDi), 0, LLVMDIFlags.Zero); -: 824: } -: 825: -: 826: @foreign function LLVMDITypeGetOffsetInBits(LLVMMetadataRef DType): u64; -: 827: alias getTypeOffset = LLVMDITypeGetOffsetInBits; -: 828: -: 829: function createLexicalBlock(LLVMMetadataRef scope; u32 line; u32 col): LLVMMetadataRef -: 830: { -: 831: @foreign function LLVMDIBuilderCreateLexicalBlock(LLVMDIBuilderRef Builder; LLVMMetadataRef Scope; LLVMMetadataRef File; u32 Line; u32 Column): LLVMMetadataRef; 6613: 832: return LLVMDIBuilderCreateLexicalBlock(b, scope, f, line, col); -: 833: } -: 834: -: 835: function createLocalVariable(LLVMMetadataRef scope; s8[] name; u32 line; LLVMMetadataRef typeDi; LLVMDIFlags flags; u32 bitAlign): LLVMMetadataRef -: 836: { -: 837: @foreign function LLVMDIBuilderCreateAutoVariable( -: 838: LLVMDIBuilderRef Builder; -: 839: LLVMMetadataRef Scope; -: 840: const s8* Name; usize NameLen; -: 841: LLVMMetadataRef File; -: 842: u32 LineNo; -: 843: LLVMMetadataRef Ty; -: 844: s32 AlwaysPreserve; -: 845: LLVMDIFlags Flags; -: 846: u32 AlignInBits): LLVMMetadataRef; 3803: 847: return LLVMDIBuilderCreateAutoVariable(b, scope, name.ptr, name.length, f, line, typeDi, true, flags, bitAlign); -: 848: } -: 849: -: 850: function createMemberType(LLVMMetadataRef scope; s8[] name; u32 line; u32 bitSize; u32 bitAlign; -: 851: u32 bitOffset; LLVMDIFlags flags; LLVMMetadataRef typeDi): LLVMMetadataRef -: 852: { -: 853: @foreign function LLVMDIBuilderCreateMemberType( -: 854: LLVMDIBuilderRef Builder; -: 855: LLVMMetadataRef Scope; -: 856: const s8* Name; usize NameLen; -: 857: LLVMMetadataRef File; -: 858: u32 LineNo; -: 859: u64 SizeInBits; -: 860: u32 AlignInBits; -: 861: u64 OffsetInBits; -: 862: LLVMDIFlags Flags; -: 863: LLVMMetadataRef Ty): LLVMMetadataRef; 12925: 864: return LLVMDIBuilderCreateMemberType(b, scope, name.ptr, name.length, f, line, bitSize, bitAlign, bitOffset, flags, typeDi); -: 865: } -: 866: -: 867: function createParameterVariable(LLVMMetadataRef scope; s8[] name; u32 argNo; u32 line; LLVMMetadataRef typeDi; LLVMDIFlags flags): LLVMMetadataRef -: 868: { -: 869: @foreign function LLVMDIBuilderCreateParameterVariable ( -: 870: LLVMDIBuilderRef Builder; -: 871: LLVMMetadataRef Scope; -: 872: const s8* Name; usize NameLen; -: 873: u32 ArgNo; -: 874: LLVMMetadataRef File; -: 875: u32 LineNo; -: 876: LLVMMetadataRef Ty; -: 877: s32 AlwaysPreserve; -: 878: LLVMDIFlags Flags): LLVMMetadataRef; 3406: 879: return LLVMDIBuilderCreateParameterVariable(b, scope, name.ptr, name.length, argNo, f, line, typeDi, true, flags); -: 880: } -: 881: -: 882: function createPointerType(LLVMMetadataRef pointee; u32 bitSz; u32 bitAlign; s8[] name): LLVMMetadataRef -: 883: { -: 884: @foreign function LLVMDIBuilderCreatePointerType(LLVMDIBuilderRef Builder; LLVMMetadataRef PointeeTy; u64 SizeInBits; u32 AlignInBits; u32 AddressSpace; const s8* Name; usize NameLen): LLVMMetadataRef; 55266: 885: return LLVMDIBuilderCreatePointerType(b, pointee, bitSz, bitAlign, 0, name.ptr, name.length); -: 886: } -: 887: -: 888: function createStaticMemberType(LLVMMetadataRef scope; s8[] name; u32 line; u32 bitAlign; LLVMDIFlags flags; LLVMMetadataRef typeDi; LLVMValueRef constVal): LLVMMetadataRef -: 889: { -: 890: @foreign function LLVMDIBuilderCreateStaticMemberType( -: 891: LLVMDIBuilderRef Builder; -: 892: LLVMMetadataRef Scope; -: 893: const s8* Name; usize NameLen; -: 894: LLVMMetadataRef File; -: 895: u32 LineNumber; -: 896: LLVMMetadataRef Type; -: 897: LLVMDIFlags Flags; -: 898: LLVMValueRef ConstantVal; -: 899: u32 AlignInBits): LLVMMetadataRef; 597: 900: return LLVMDIBuilderCreateStaticMemberType(b, scope, name.ptr, name.length, f, line, typeDi, flags, constVal, bitAlign); -: 901: } -: 902: -: 903: function createStructType(LLVMMetadataRef scope; s8[] name; u32 line; u32 bitSize; u32 bitAlign; LLVMDIFlags flags; LLVMMetadataRef[] members): LLVMMetadataRef -: 904: { -: 905: @foreign function LLVMDIBuilderCreateStructType( -: 906: LLVMDIBuilderRef Builder; -: 907: LLVMMetadataRef Scope; -: 908: const s8* Name; usize NameLen; -: 909: LLVMMetadataRef File; -: 910: u32 LineNumber; -: 911: u64 SizeInBits; -: 912: u32 AlignInBits; -: 913: LLVMDIFlags Flags; -: 914: LLVMMetadataRef DerivedFrom; -: 915: LLVMMetadataRef* Elements; u32 NumElements; -: 916: u32 RunTimeLang; -: 917: LLVMMetadataRef VTableHolder; -: 918: const s8* UniqueId; usize UniqueIdLen): LLVMMetadataRef; 2355: 919: return LLVMDIBuilderCreateStructType(b, scope, name.ptr, name.length, f, line, bitSize, bitAlign, flags, null, -: 920: members.ptr, members.length:u32, 0, null, name.ptr, name.length); -: 921: } -: 922: -: 923: function createSubroutineType(LLVMMetadataRef[] paramsTypeDi; LLVMDIFlags flags): LLVMMetadataRef -: 924: { -: 925: @foreign function LLVMDIBuilderCreateSubroutineType(LLVMDIBuilderRef Builder; LLVMMetadataRef File; LLVMMetadataRef* ParameterTypes; u32 NumParameterTypes; LLVMDIFlags Flags): LLVMMetadataRef; 2121: 926: return LLVMDIBuilderCreateSubroutineType(b, f, paramsTypeDi.ptr, paramsTypeDi.length:u32, flags); -: 927: } -: 928: -: 929: function createUnionType(LLVMMetadataRef scope; s8[] name; u32 line; u32 bitSize; u32 bitAlign; LLVMDIFlags flags; LLVMMetadataRef[] members): LLVMMetadataRef -: 930: { -: 931: @foreign function LLVMDIBuilderCreateUnionType ( -: 932: LLVMDIBuilderRef Builder; -: 933: LLVMMetadataRef Scope; -: 934: const s8* Name; usize NameLen; -: 935: LLVMMetadataRef File; -: 936: u32 LineNumber; -: 937: u64 SizeInBits; -: 938: u32 AlignInBits; -: 939: LLVMDIFlags Flags; -: 940: LLVMMetadataRef* Elements; u32 NumElements; -: 941: u32 RunTimeLang; -: 942: const s8* UniqueId; usize UniqueIdLen): LLVMMetadataRef; 1: 943: return LLVMDIBuilderCreateUnionType(b, scope, name.ptr, name.length, f, line, bitSize, bitAlign, flags, members.ptr, members.length:u32, 0, name.ptr, name.length); -: 944: } -: 945: -: 946: function createUnspecifiedType(s8[] name): LLVMMetadataRef -: 947: { -: 948: @foreign function LLVMDIBuilderCreateUnspecifiedType(LLVMDIBuilderRef Builder; const s8* Name; usize NameLen): LLVMMetadataRef; 73: 949: return LLVMDIBuilderCreateUnspecifiedType(b, name.ptr, name.length); -: 950: } -: 951:} -: 952: -: 953: -: 954:@foreign struct LLVMOpaqueContext; -: 955:alias LLVMContextRef = LLVMOpaqueContext*; -: 956: -: 957:@foreign function LLVMContextCreate(): LLVMContextRef; -: 958:@foreign function LLVMGetGlobalContext(): LLVMContextRef; -: 959:@foreign function LLVMContextDispose(LLVMContextRef c); -: 960: -: 961:@foreign struct LLVMOpaqueBuilder; -: 962:alias LLVMBuilderRef = LLVMOpaqueBuilder*; -: 963: -: 964:@foreign function LLVMCreateBuilderInContext(LLVMContextRef C): LLVMBuilderRef; -: 965:@foreign function LLVMDisposeBuilder(LLVMBuilderRef Builder); -: 966: -: 967:@foreign struct LLVMOpaqueModule; -: 968:alias LLVMModuleRef = LLVMOpaqueModule*; -: 969: -: 970:@foreign struct LLVMOpaqueValue; -: 971:alias LLVMValueRef = LLVMOpaqueValue*; -: 972:alias ValueRef = LLVMOpaqueValue*; -: 973: -: 974:@foreign function LLVMGetInstructionOpcode(LLVMValueRef Inst): u32; -: 975:@foreign function LLVMIsConstant(LLVMValueRef Val): s32; -: 976: -: 977:@foreign function LLVMValueAsMetadata(LLVMValueRef Val): LLVMMetadataRef; -: 978:@foreign function LLVMModuleCreateWithNameInContext(s8* name; LLVMContextRef ctxt): LLVMModuleRef; -: 979:@foreign function LLVMDisposeModule(LLVMModuleRef M); -: 980:@foreign function LLVMAddModuleFlag(LLVMModuleRef M; LLVMModuleFlagBehavior Behavior; s8* Key; usize KeyLen; LLVMMetadataRef Val); -: 981:@foreign function LLVMGlobalSetMetadata(LLVMValueRef Global; u32 Kind; LLVMMetadataRef MD); -: 982:@foreign function LLVMInstructionSetDebugLoc(LLVMValueRef Inst; LLVMMetadataRef Loc); -: 983: -: 984:@foreign struct LLVMOpaqueDIBuilder; -: 985:alias LLVMDIBuilderRef = LLVMOpaqueDIBuilder*; -: 986: -: 987:@foreign struct LLVMOpaqueBasicBlock; -: 988:alias LLVMBasicBlockRef = LLVMOpaqueBasicBlock*; -: 989: -: 990:@foreign struct LLVMOpaqueType; -: 991:alias LLVMTypeRef = LLVMOpaqueType*; -: 992: -: 993:@foreign struct LLVMOpaqueMetadata; -: 994:alias LLVMMetadataRef = LLVMOpaqueMetadata*; -: 995: -: 996:@foreign function LLVMDisposeMessage(s8* c); -: 997: -: 998:@foreign struct LLVMOpaquePassManagerBuilder; -: 999:alias LLVMPassManagerBuilderRef = LLVMOpaquePassManagerBuilder*; -:1000: -:1001:@foreign struct LLVMOpaquePassManager; -:1002:alias LLVMPassManagerRef = LLVMOpaquePassManager*; -:1003: -:1004:@foreign struct LLVMOpaqueMemoryBuffer; -:1005:alias LLVMMemoryBufferRef = LLVMOpaqueMemoryBuffer*; -:1006: -:1007:@foreign struct LLVMOpaqueAttribute; -:1008:alias LLVMAttributeRef = LLVMOpaqueAttribute*; -:1009: -:1010:@foreign struct LLVMTarget; -:1011:alias LLVMTargetRef = LLVMTarget*; -:1012: -:1013:@foreign struct LLVMOpaqueTargetMachine; -:1014:alias LLVMTargetMachineRef = LLVMOpaqueTargetMachine*; -:1015: -:1016:enum LLVMModuleFlagBehavior -:1017:{ -:1018: /** -:1019: * Emits an error if two values disagree, otherwise the resulting value is -:1020: * that of the operands. -:1021: * -:1022: * @see Module::ModFlagBehavior::Error -:1023: */ -:1024: Error = 0, -:1025: /** -:1026: * Emits a warning if two values disagree. The result value will be the -:1027: * operand for the flag from the first module being linked. -:1028: * -:1029: * @see Module::ModFlagBehavior::Warning -:1030: */ -:1031: Warning = 1, -:1032: /** -:1033: * Adds a requirement that another module flag be present and have a -:1034: * specified value after linking is performed. The value must be a metadata -:1035: * pair, where the first element of the pair is the ID of the module flag -:1036: * to be restricted, and the second element of the pair is the value the -:1037: * module flag should be restricted to. This behavior can be used to -:1038: * restrict the allowable results (via triggering of an error) of linking -:1039: * IDs with the **Override** behavior. -:1040: * -:1041: * @see Module::ModFlagBehavior::Require -:1042: */ -:1043: Require = 2, -:1044: /** -:1045: * Uses the specified value, regardless of the behavior or value of the -:1046: * other module. If both modules specify **Override**, but the values -:1047: * differ, an error will be emitted. -:1048: * -:1049: * @see Module::ModFlagBehavior::Override -:1050: */ -:1051: Override = 3, -:1052: /** -:1053: * Appends the two values, which are required to be metadata nodes. -:1054: * -:1055: * @see Module::ModFlagBehavior::Append -:1056: */ -:1057: Append = 4, -:1058: /** -:1059: * Appends the two values, which are required to be metadata -:1060: * nodes. However, duplicate entries in the second list are dropped -:1061: * during the append operation. -:1062: * -:1063: * @see Module::ModFlagBehavior::AppendUnique -:1064: */ -:1065: AppendUnique = 5 -:1066:} -:1067: -:1068:enum LLVMRelocMode -:1069:{ -:1070: Default = 0, -:1071: Static = 1, -:1072: PIC = 2, -:1073: DynamicNoPic = 3, -:1074: ROPI = 4, -:1075: RWPI = 5, -:1076: ROPI_RWPI = 6 -:1077:} -:1078: -:1079:enum LLVMCodeModel -:1080:{ -:1081: Default = 0, -:1082: JITDefault = 1, -:1083: Tiny = 2, -:1084: Small = 3, -:1085: Kernel = 4, -:1086: Medium = 5, -:1087: Large = 6 -:1088:} -:1089: -:1090:enum LLVMCodeGenFileType : u32 -:1091:{ -:1092: AssemblyFile = 0, -:1093: ObjectFile = 1 -:1094:} -:1095: -:1096:enum LLVMCodeGenOptLevel -:1097:{ -:1098: None = 0, -:1099: Less = 1, -:1100: Default = 2, -:1101: Aggressive = 3 -:1102:} -:1103: -:1104:enum LLVMVerifierFailureAction -:1105:{ -:1106: AbortProcessAction = 0, /* verifier will print to stderr and abort() */ -:1107: PrintMessageAction = 1, /* verifier will print to stderr and return 1 */ -:1108: ReturnStatusAction = 2 /* verifier will just return 1 */ -:1109:} -:1110: -:1111:enum LLVMIntPredicate -:1112:{ -:1113: EQ = 32, /**< equal */ -:1114: NE = 33, /**< not equal */ -:1115: UGT = 34, /**< unsigned greater than */ -:1116: UGE = 35, /**< unsigned greater or equal */ -:1117: ULT = 36, /**< unsigned less than */ -:1118: ULE = 37, /**< unsigned less or equal */ -:1119: SGT = 38, /**< signed greater than */ -:1120: SGE = 39, /**< signed greater or equal */ -:1121: SLT = 40, /**< signed less than */ -:1122: SLE = 41 /**< signed less or equal */ -:1123:} -:1124: -:1125:enum LLVMRealPredicate -:1126:{ -:1127: OFalse = 0, /**< Always false (always folded) */ -:1128: OEQ = 1, /**< True if ordered and equal */ -:1129: OGT = 2, /**< True if ordered and greater than */ -:1130: OGE = 3, /**< True if ordered and greater than or equal */ -:1131: OLT = 4, /**< True if ordered and less than */ -:1132: OLE = 5, /**< True if ordered and less than or equal */ -:1133: ONE = 6, /**< True if ordered and operands are unequal */ -:1134: ORD = 7, /**< True if ordered (no nans) */ -:1135: UNO = 8, /**< True if unordered: isnan(X) | isnan(Y) */ -:1136: UEQ = 9, /**< True if unordered or equal */ -:1137: UGT = 10, /**< True if unordered or greater than */ -:1138: UGE = 11, /**< True if unordered, greater than, or equal */ -:1139: ULT = 12, /**< True if unordered or less than */ -:1140: ULE = 13, /**< True if unordered, less than, or equal */ -:1141: UNE = 14, /**< True if unordered or not equal */ -:1142: OTrue = 15 /**< Always true (always folded) */ -:1143:} -:1144: -:1145:@foreign function LLVMVerifyModule(LLVMModuleRef m; LLVMVerifierFailureAction action; s8** OutMessage): s32; -:1146: -:1147:@foreign function LLVMPointerType(LLVMTypeRef ElementType; s32 AddressSpace): LLVMTypeRef; -:1148: -:1149:@foreign function LLVMLookupIntrinsicID (const s8* Name; usize NameLen): u32; -:1150: -:1151:@foreign function LLVMIntrinsicGetType(LLVMContextRef Ctx; u32 ID; LLVMTypeRef* ParamTypes; usize ParamCount): LLVMTypeRef; -:1152: -:1153:@foreign function LLVMGetIntrinsicDeclaration(LLVMModuleRef Mod; u32 ID; LLVMTypeRef* ParamTypes; usize ParamCount): LLVMValueRef; -:1154: -:1155:@foreign function LLVMTypeOf(LLVMValueRef value): LLVMTypeRef; -:1156: -:1157:@foreign function LLVMAddAttributeAtIndex(LLVMValueRef F; LLVMAttributeIndex Idx; LLVMAttributeRef A); -:1158: -:1159:@foreign function LLVMAppendModuleInlineAsm(LLVMModuleRef M; const s8* Asm; usize Len); -:1160: -:1161:enum LLVMAttributeIndex : s32 -:1162:{ -:1163: Return = 0, // apply to the return -:1164: Param1 = 1, // apply to first parameter -:1165: Param2 = 2, // apply to the second parameter -:1166: //.... -:1167: Function = -1, // apply to the function -:1168:} -:1169: -:1170:@foreign function LLVMSetInitializer(LLVMValueRef GlobalVar; LLVMValueRef ConstantVal); -:1171: -:1172:enum LLVMLinkage -:1173:{ -:1174: ExternalLinkage = 0, /**< Externally visible function */ -:1175: AvailableExternallyLinkage = 1, -:1176: LinkOnceAnyLinkage = 2, /**< Keep one copy of function when linking (inline)*/ -:1177: LinkOnceODRLinkage = 3, /**< Same, but only replaced by something equivalent. */ -:1178: LinkOnceODRAutoHideLinkage = 4, /**< Obsolete */ -:1179: WeakAnyLinkage = 5, /**< Keep one copy of function when linking (weak) */ -:1180: WeakODRLinkage = 6, /**< Same, but only replaced by something equivalent. */ -:1181: AppendingLinkage = 7, /**< Special purpose, only applies to global arrays */ -:1182: InternalLinkage = 8, /**< Rename collisions when linking (staticfunctions) */ -:1183: PrivateLinkage = 9, /**< Like Internal, but omit from symbol table */ -:1184: DLLImportLinkage = 10, /**< Obsolete */ -:1185: DLLExportLinkage = 11, /**< Obsolete */ -:1186: ExternalWeakLinkage = 12, /**< ExternalWeak linkage description */ -:1187: GhostLinkage = 13, /**< Obsolete */ -:1188: CommonLinkage = 14, /**< Tentative definitions */ -:1189: LinkerPrivateLinkage = 15, /**< Like Private, but linker removes. */ -:1190: LinkerPrivateWeakLinkage = 16 /**< Like LinkerPrivate, but is weak. */ -:1191:} -:1192: -:1193:@foreign function LLVMGetParam(LLVMValueRef Fn; u32 Index): LLVMValueRef; -:1194: -:1195:@foreign function LLVMAddGlobal(LLVMModuleRef M; LLVMTypeRef Ty; const s8* Name = ""): LLVMValueRef; -:1196: -:1197:@foreign function LLVMSetThreadLocalMode(LLVMValueRef GlobalVar; LLVMThreadLocalMode Mode); -:1198: -:1199:@foreign function LLVMAddFunction(LLVMModuleRef M; const s8* Name; LLVMTypeRef FunctionTy): LLVMValueRef; -:1200: -:1201:@foreign function LLVMSetLinkage(LLVMValueRef Global; LLVMLinkage Linkage); -:1202: -:1203:@foreign function LLVMFunctionType(LLVMTypeRef ReturnType; LLVMTypeRef* ParamTypes; u32 ParamCount; s32 IsVarArg): LLVMTypeRef; -:1204: -:1205:@foreign function LLVMStructTypeInContext(LLVMContextRef C; LLVMTypeRef* ElementTypes; u32 ElementCount; s32 Packed): LLVMTypeRef; -:1206: -:1207:@foreign function LLVMFloatTypeInContext(LLVMContextRef C): LLVMTypeRef; -:1208:@foreign function LLVMDoubleTypeInContext(LLVMContextRef C): LLVMTypeRef; -:1209:@foreign function LLVMVoidTypeInContext(LLVMContextRef C): LLVMTypeRef; -:1210:@foreign function LLVMInt1TypeInContext(LLVMContextRef C): LLVMTypeRef; -:1211:@foreign function LLVMInt8TypeInContext(LLVMContextRef C): LLVMTypeRef; -:1212:@foreign function LLVMInt16TypeInContext(LLVMContextRef C): LLVMTypeRef; -:1213:@foreign function LLVMInt32TypeInContext(LLVMContextRef C): LLVMTypeRef; -:1214:@foreign function LLVMInt64TypeInContext(LLVMContextRef C): LLVMTypeRef; -:1215: -:1216:@foreign function LLVMGetTypeKind(LLVMTypeRef Ty): LLVMTypeKind; -:1217: -:1218:enum LLVMThreadLocalMode -:1219:{ -:1220: NotThreadLocal = 0, -:1221: GeneralDynamicTLSModel = 1, -:1222: LocalDynamicTLSModel = 2, -:1223: InitialExecTLSModel = 3, -:1224: LocalExecTLSModel = 4 -:1225:} -:1226: -:1227:enum LLVMTypeKind -:1228:{ -:1229: VoidTypeKind = 0, /**< type with no size */ -:1230: HalfTypeKind = 1, /**< 16 bit floating point type */ -:1231: FloatTypeKind = 2, /**< 32 bit floating point type */ -:1232: DoubleTypeKind = 3, /**< 64 bit floating point type */ -:1233: X86_FP80TypeKind = 4, /**< 80 bit floating point type (X87) */ -:1234: FP128TypeKind = 5, /**< 128 bit floating point type (112-bit mantissa)*/ -:1235: PPC_FP128TypeKind = 6, /**< 128 bit floating point type (two 64-bits) */ -:1236: LabelTypeKind = 7, /**< Labels */ -:1237: IntegerTypeKind = 8, /**< Arbitrary bit width integers */ -:1238: FunctionTypeKind = 9, /**< Functions */ -:1239: StructTypeKind = 10, /**< Structures */ -:1240: ArrayTypeKind = 11, /**< Arrays */ -:1241: PointerTypeKind = 12, /**< Pointers */ -:1242: VectorTypeKind = 13, /**< Fixed width SIMD vector type */ -:1243: MetadataTypeKind = 14, /**< Metadata */ -:1244: X86_MMXTypeKind = 15, /**< X86 MMX */ -:1245: TokenTypeKind = 16, /**< Tokens */ -:1246: ScalableVectorTypeKind = 17, /**< Scalable SIMD vector type */ -:1247: BFloatTypeKind = 18 /**< 16 bit brain floating point type */ -:1248:} -:1249: -:1250:enum DWARF_ENCODING : u32 -:1251:{ -:1252: address = 0x01, -:1253: boolean = 0x02, -:1254: complex_float = 0x03, -:1255: float = 0x04, -:1256: signed = 0x05, -:1257: signed_char = 0x06, -:1258: unsigned = 0x07, -:1259: unsigned_char = 0x08, -:1260: imaginary_float = 0x09, -:1261: packed_decimal = 0x0a, -:1262: numeric_string = 0x0b, -:1263: edited = 0x0c, -:1264: signed_fixed = 0x0d, -:1265: unsigned_fixed = 0x0e, -:1266: decimal_float = 0x0f, -:1267: lo_user = 0x80, -:1268: hi_user = 0xff -:1269:} -:1270: -:1271:/** -:1272: * Debug info flags. -:1273: */ -:1274:enum LLVMDIFlags -:1275:{ -:1276: Zero = 0, -:1277: Private = 1, -:1278: Protected = 2, -:1279: Public = 3, -:1280: FwdDecl = 1 << 2, -:1281: AppleBlock = 1 << 3, -:1282: ReservedBit4 = 1 << 4, -:1283: Virtual = 1 << 5, -:1284: Artificial = 1 << 6, -:1285: Explicit = 1 << 7, -:1286: Prototyped = 1 << 8, -:1287: ObjcClassComplete = 1 << 9, -:1288: ObjectPointer = 1 << 10, -:1289: Vector = 1 << 11, -:1290: StaticMember = 1 << 12, -:1291: LValueReference = 1 << 13, -:1292: RValueReference = 1 << 14, -:1293: Reserved = 1 << 15, -:1294: SingleInheritance = 1 << 16, -:1295: MultipleInheritance = 2 << 16, -:1296: VirtualInheritance = 3 << 16, -:1297: IntroducedVirtual = 1 << 18, -:1298: BitField = 1 << 19, -:1299: NoReturn = 1 << 20, -:1300: TypePassByValue = 1 << 22, -:1301: TypePassByReference = 1 << 23, -:1302: EnumClass = 1 << 24, -:1303: //FixedEnum = LLVMDIFlags.EnumClass, // Deprecated. -:1304: Thunk = 1 << 25, -:1305: NonTrivial = 1 << 26, -:1306: BigEndian = 1 << 27, -:1307: LittleEndian = 1 << 28, -:1308: IndirectVirtualBase = (1 << 2) | (1 << 5), -:1309: //Accessibility = LLVMDIFlags.Private | LLVMDIFlags.Protected | LLVMDIFlags.Public, -:1310: //PtrToMemberRep = LLVMDIFlags.SingleInheritance | LLVMDIFlags.MultipleInheritance | LLVMDIFlags.VirtualInheritance -:1311:} -:1312: -:1313:enum LLVMInlineAsmDialect -:1314:{ -:1315: ATT = 0, -:1316: Intel = 1 -:1317:} -:1318: -:1319:@foreign function LLVMGetInlineAsm (LLVMTypeRef Ty; s8* AsmString; usize AsmStringSize; s8* Constraints; -:1320: usize ConstraintsSize; s32 HasSideEffects; s32 IsAlignStack; LLVMInlineAsmDialect Dialect; s32 CanThrow = 0): LLVMValueRef; -:1321: -:1322:@foreign function LLVMStructCreateNamed(LLVMContextRef C; const s8* Name): LLVMTypeRef; -:1323: -:1324:@foreign function LLVMStructSetBody(LLVMTypeRef StructTy; LLVMTypeRef* ElementTypes; s32 ElementCount; s32 Packed); -:1325: -:1326:@foreign function LLVMArrayType(LLVMTypeRef ElementType; s32 ElementCount): LLVMTypeRef; -:1327: -:1328:@foreign function LLVMSetFunctionCallConv(LLVMValueRef Fn; u32 CC); -:1329: -:1330:enum LLVMCallConv -:1331:{ -:1332: CCallConv = 0, -:1333: FastCallConv = 8, -:1334: ColdCallConv = 9, -:1335: GHCCallConv = 10, -:1336: HiPECallConv = 11, -:1337: WebKitJSCallConv = 12, -:1338: AnyRegCallConv = 13, -:1339: PreserveMostCallConv = 14, -:1340: PreserveAllCallConv = 15, -:1341: SwiftCallConv = 16, -:1342: CXXFASTTLSCallConv = 17, -:1343: X86StdcallCallConv = 64, -:1344: X86FastcallCallConv = 65, -:1345: ARMAPCSCallConv = 66, -:1346: ARMAAPCSCallConv = 67, -:1347: ARMAAPCSVFPCallConv = 68, -:1348: MSP430INTRCallConv = 69, -:1349: X86ThisCallCallConv = 70, -:1350: PTXKernelCallConv = 71, -:1351: PTXDeviceCallConv = 72, -:1352: SPIRFUNCCallConv = 75, -:1353: SPIRKERNELCallConv = 76, -:1354: IntelOCLBICallConv = 77, -:1355: X8664SysVCallConv = 78, -:1356: Win64CallConv = 79, -:1357: X86VectorCallCallConv = 80, -:1358: HHVMCallConv = 81, -:1359: HHVMCCallConv = 82, -:1360: X86INTRCallConv = 83, -:1361: AVRINTRCallConv = 84, -:1362: AVRSIGNALCallConv = 85, -:1363: AVRBUILTINCallConv = 86, -:1364: AMDGPUVSCallConv = 87, -:1365: AMDGPUGSCallConv = 88, -:1366: AMDGPUPSCallConv = 89, -:1367: AMDGPUCSCallConv = 90, -:1368: AMDGPUKERNELCallConv = 91, -:1369: X86RegCallCallConv = 92, -:1370: AMDGPUHSCallConv = 93, -:1371: MSP430BUILTINCallConv = 94, -:1372: AMDGPULSCallConv = 95, -:1373: AMDGPUESCallConv = 96 -:1374:} -:1375: -:1376:/// Source languages known by DWARF. -:1377:enum LLVMDWARFSourceLanguage -:1378:{ -:1379: C89 = 0, -:1380: C = 1, -:1381: Ada83 = 2, -:1382: C_plus_plus = 3, -:1383: Cobol74 = 4, -:1384: Cobol85 = 5, -:1385: Fortran77 = 6, -:1386: Fortran90 = 7, -:1387: Pascal83 = 8, -:1388: Modula2 = 9, -:1389: // New in DWARF v3: -:1390: Java = 10, -:1391: C99 = 11, -:1392: Ada95 = 12, -:1393: Fortran95 = 13, -:1394: PLI = 14, -:1395: ObjC = 15, -:1396: ObjC_plus_plus = 16, -:1397: UPC = 17, -:1398: D = 18, -:1399: // New in DWARF v4: -:1400: Python = 19, -:1401: // New in DWARF v5: -:1402: OpenCL = 20, -:1403: Go = 21, -:1404: Modula3 = 22, -:1405: Haskell = 23, -:1406: C_plus_plus_03 = 24, -:1407: C_plus_plus_11 = 25, -:1408: OCaml = 26, -:1409: Rust = 27, -:1410: C11 = 28, -:1411: Swift = 29, -:1412: Julia = 30, -:1413: Dylan = 31, -:1414: C_plus_plus_14 = 32, -:1415: Fortran03 = 33, -:1416: Fortran08 = 34, -:1417: RenderScript = 35, -:1418: BLISS = 36, -:1419: // Vendor extensions: -:1420: Mips_Assembler = 37, -:1421: GOOGLE_RenderScript = 38, -:1422: BORLAND_Delphi = 39 -:1423:} -:1424: -:1425:/// The amount of debug information to emit. -:1426:enum LLVMDWARFEmissionKind -:1427:{ -:1428: None = 0, -:1429: Full = 1, -:1430: LineTablesOnly = 2 -:1431:} <<<<<< EOF # path=src/styx/semantic/bodies.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/semantic/bodies.sx -: 1:unit styx.semantic.bodies; -: 2: -: 3:@private import -: 4: styx.ast.base, -: 5: styx.ast.declarations, -: 6: styx.ast.formatter, -: 7: styx.ast.statements, -: 8: styx.ast.expressions, -: 9: styx.ast.types, -: 10: styx.ast.visitor, -: 11: styx.semantic.expressions, -: 12: styx.semantic.statements, -: 13: styx.semantic.memulator, -: 14: styx.session, -: 15: styx.symbol, -: 16: ; -: 17: -: 18:/// Perform semantic checks for all function bodies in a given compilation unit. -: 19:function bodiesSemantic(UnitDeclaration* node) -: 20:{ -: 21: @final class BodyVisitor : AstVisitor -: 22: { -: 23: var FunctionDeclaration* curr; -: 24: -: 25: @override function visitAliasDeclaration(AliasDeclaration* node) -: 26: { -: 27: // Applied generics have an AST which is not inserted in the -: 28: // AST produced by parsing the source code. -: 29: // -: 30: // This allows to visit member functions bodies located in those -: 31: // "dangling" trees. 343: 32: if node.exp && node.sourceSymbol do -: 33: { 99: 34: var auto d = node.sourceSymbol.astNode.asDeclaration(); 99: 35: visitConcreteDeclaration(d); -: 36: } -: 37: // same, but for TypeAppliedGeneric that gave a TypeDeclared 244: 38: else do if node.type do 244: 39: visitType(node.type); 343: 40: } -: 41: -: 42: @override function visitApplyExpression(ApplyExpression* node) -: 43: { -: 44: // process bodies in applied member functions 8: 45: var auto t = node.type.resolved(); 16: 46: if var Symbol* ds = t.asSymbol() do 14: 47: if var auto d = ds.astNode.asDeclaration() do 7: 48: visitConcreteDeclaration(d); 8: 49: } -: 50: -: 51: @override function visitClassDeclaration(ClassDeclaration* node) -: 52: { 476: 53: memulate(node, node.scope); 476: 54: if !node.isGeneric() do 476: 55: node.accept(this); 476: 56: } -: 57: -: 58: @override function visitDeclaration(Declaration* node) -: 59: { 15631: 60: if !node.isGeneric() && (!node.symbol || !node.symbol.recurseGuard) do -: 61: { 30169: 62: if node.symbol do node.symbol.recurseGuard++; 15471: 63: visitConcreteDeclaration(node); 30169: 64: if node.symbol do node.symbol.recurseGuard--; -: 65: } 15631: 66: } -: 67: -: 68: @override function visitExpression(Expression* node) -: 69: { -: 70: // exps that can apply a generic 32146: 71: if node.operator == $apply || node.operator == colon || node.operator == eopLambda || node.operator == $new do 1232: 72: visitConcreteExpression(node); 32146: 73: } -: 74: -: 75: @override function visitFunctionDeclaration(FunctionDeclaration* node) -: 76: { 5094: 77: if node:u8* == curr:u8* do // tests: dyna_array.sx / bad_eval.sx / nested_func.sx 5: 78: return; // exibits a problem of inf. recursion 5089: 79: curr = node; 5089: 80: if node.body do -: 81: { -: 82: // test for isGeneric in this func as bodySemantic() can be called -: 83: // directly from expsema 4424: 84: bodySemantic(node); 4424: 85: node.body.accept(this); -: 86: } 5089: 87: } -: 88: -: 89: @override function visitStructDeclaration(StructDeclaration* node) -: 90: { 479: 91: memulate(node, node.scope); 479: 92: if !node.isGeneric() do 467: 93: node.accept(this); 479: 94: } -: 95: -: 96: @override function visitTypeClass(const TypeClass* node) -: 97: { 387: 98: visitTypeDeclared(node); 387: 99: } -:100: -:101: function visitTypeDeclared(TypeDeclared* node) -:102: { 650:103: if node.declaration?.genericParameters do 44:104: visitConcreteDeclaration(node.declaration); 650:105: } -:106: -:107: @override function visitTypeFunction(const TypeFunction* node) -:108: { 170:109: visitTypeDeclared(node); 170:110: } -:111: -:112: @override function visitTypeStruct(const TypeStruct* node) -:113: { 91:114: visitTypeDeclared(node); 91:115: } -:116: -:117: @override function visitTypeUnion(const TypeUnion* node) -:118: { 2:119: visitTypeDeclared(node); 2:120: } -:121: -:122: @override function visitUnionDeclaration(UnionDeclaration* node) -:123: { 27:124: memulate(node, node.scope); 27:125: if !node.isGeneric() do 27:126: node.accept(this); 27:127: } -:128: } -:129: var BodyVisitor bv; 472:130: bv.visitDeclaration(node); 472:131:} -:132: -:133:/// Perform semantic checks the specified function body. -:134:function bodySemantic(FunctionDeclaration* node) -:135:{ 4670:136: if node.isGeneric() || isInGeneric in node.scope.flags do 6:137: return; -:138: //printf("%s\n", format(node/*, testMode*/).ptr); 4664:139: assert(node.progress == SemanticProgress.done); -:140: 4664:141: if !node.body || node.bodyDone do 141:142: return; 4523:143: node.bodyDone = true; -:144: 4523:145: var BlockStatement* bs = asBlockStatement(node.body); 4523:146: statementSemantic(bs, bs.scope); -:147: 4523:148: var Type* t = node.returnType.resolved(); 4523:149: if isTypeAuto(t) do 79:150: processAutoFunctionReturns(node); -:151: 4523:152: if !bs.flow.isReturn() && !bs.flow.isContinue() do -:153: { 2293:154: if bs.flow.isNoReturn() do 1:155: session.error(node.scope.filename, bs.stopPos, "cannot implictly return after a call to an `@noreturn` function"); 2293:156: if isTypeVoid(node.returnType.resolved()) do -:157: { 2288:158: var ReturnStatement* rs = (new ReturnStatement).create(bs.stopPos); 2288:159: rs.stopPos = bs.stopPos; 2288:160: bs.statements ~= rs; 2288:161: statementSemantic(rs, bs.scope); 2288:162: bs.flow.mixLinear(rs.flow); -:163: } -:164: else do -:165: { 5:166: session.error(node.scope.filename, bs.stopPos, "expected return statement"); -:167: } -:168: } -:169: 4523:170: if node.escapes && (session.optLevel || session.escapeUsed) && isNested !in node.flags do 10:171: checkEscapeUsed(node); 4523:172:} -:173: -:174:/// Partially prevent escapes that are used to access static members to create slower code -:175:function checkEscapeUsed(FunctionDeclaration* node; const bool isLambda = false) -:176:{ -:177: @final class EscapeUsedVisitor : AstVisitor -:178: { -:179: static var FunctionDeclaration* that; -:180: static var bool inNested; -:181: -:182: @override function visitExpression(Expression* node) -:183: { 228:184: if inNested do visitConcreteExpression(node); 116:185: } -:186: -:187: @override function visitDotExpression(DotExpression* node) -:188: { 18:189: node.accept(this); 18:190: var auto ed = symToVarDecl(node.expression.symbol); 18:191: var auto vd = symToVarDecl(node.dotted.symbol); 18:192: var auto fd = symToFuncDecl(node.dotted.symbol); 18:193: if ed && ed.escapeUsed do 36:194: if var auto d = vd ? fd do -:195: { -:196: // dont use the type of the dot LHS: -:197: // 1. because the dot LHS can be a pointer to an aggr instance -:198: // 2. that allows to skip global static functions 18:199: var auto t = d.symbol.parent.asType(); -:200: 18:201: if t && d.isStatic() do -:202: { 14:203: const auto o = node.expression; -:204: // `escapeVar.staticMember` -> `AggregateType.staticMember` 14:205: node.expression = (new TypeExpression).create(node.expression.startPos, t, true); 14:206: ed.escapeUsed--; 14:207: if session.vescapeUsed do 14:208: printf("%s:%d:%d: rewritten `%s.%s` to `%s`\n", that.scope.filename.ptr, node.startPos.line, node.startPos.column, -:209: format(o).ptr, format(node.dotted).ptr, format(node).ptr); -:210: } -:211: } 18:212: } -:213: -:214: @override function visitFunctionDeclaration(FunctionDeclaration* node) -:215: { 43:216: const auto o = inNested; 43:217: inNested = isNested in node.flags; 43:218: visitConcreteStatement(node.body); 43:219: inNested = o; 43:220: } -:221: } -:222: -:223: static var EscapeUsedVisitor euv; -:224: // lambda bodies are checked before the parent function, 34:225: if (euv.that = isLambda ? node.scope.pop().func else node) do 33:226: euv.visitConcreteDeclaration(node); -:227: 34:228: const auto old = node.escapes.dup; -:229: var u32 j; 34:230: foreach const auto vd in old do -:231: { 12:232: if vd.escapeUsed do -:233: { 5:234: vd.escapeIndex = j; 5:235: node.escapes[j++] = vd; -:236: } 7:237: else do if session.vescapeUsed do 7:238: printf("%s:%d:%d: unflaged `%s` for escaping\n", node.scope.filename.ptr, vd.startPos.line, vd.startPos.column, format(vd).ptr); -:239: } 34:240: node.escapes.length = j; 34:241:} -:242: -:243:/** -:244: * Infer the type of an auto function. -:245: * -:246: * The first return found lexicographically defines a type. -:247: * Implicit conversion to this type is then tried for all following -:248: * return statement. -:249: * -:250: * After the call and if no error was emitted then the function return -:251: * type is replaced. -:252: * -:253: * BUGS: -:254: * - may require invalid branches supression of e.g (if (echo())) -:255: */ -:256:function processAutoFunctionReturns(FunctionDeclaration* node) -:257:{ -:258: var AutoReturnVisitor arv; 79:259: arv.visitFunctionDeclaration(node); 79:260:} -:261: -:262:protection (private) -:263: -:264:@final class AutoReturnVisitor : AstVisitor -:265:{ -:266: var ReturnStatement*[+] returns; -:267: var bool nested; -:268: -:269: @destructor function destroy() -:270: { 79:271: returns.decref; 79:272: } -:273: -:274: @override function visitReturnStatement(const ReturnStatement* node) -:275: { 85:276: returns ~= node; 85:277: } -:278: 45:279: @override function visitExpressionStatement(const ExpressionStatement* node){} 12:280: @override function visitAssertStatement(const AssertStatement* node){} 236:281: @override function visitType(const Type* node){} -:282: -:283: @override function visitFunctionDeclaration(FunctionDeclaration* node) -:284: { 85:285: if nested do 6:286: return; 79:287: nested = true; 79:288: node.accept(this); -:289: -:290: var Type* commonType; 79:291: foreach (const auto i; const auto r) in returns do -:292: { 85:293: var auto e = r.expression; 85:294: if i == 0 do 78:295: continue commonType = e ? e.type.resolved() else TypeVoid.instance(); 7:296: if e do 6:297: e = implicitConvTo(e, commonType, node.scope); 7:298: if !e do -:299: { 2:300: error(node.scope.filename, returns.ptr[i].startPos, "return expression expected to be of type `%s`", format(commonType).ptr); 2:301: return; -:302: } 5:303: r.expression = e; -:304: } 77:305: if !commonType || isTypeAuto(commonType) do -:306: { 3:307: error(node.scope.filename, node.startPos, "cannot determine the return type of `%s`", node.name.text().ptr); 3:308: commonType = TypeError.instance(); -:309: } 77:310: node.returnType = commonType; 77:311: if commonType.kind == tkSlice do 1:312: error(node.scope.filename, node.startPos, "function can only return ref-counted and static arrays, not `%s` which is an array slice", format(commonType).ptr); 77:313: } -:314:} <<<<<< EOF # path=src/styx/semantic/declarations.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/semantic/declarations.sx -: 1:unit styx.semantic.declarations; -: 2: -: 3:@private import -: 4: styx.ast.base, -: 5: styx.ast.declarations, -: 6: styx.ast.expressions, -: 7: styx.ast.formatter, -: 8: styx.ast.statements, -: 9: styx.ast.types, -: 10: styx.ast.visitor, -: 11: styx.position, -: 12: styx.scope, -: 13: styx.semantic.deprecations, -: 14: styx.semantic.expressions, -: 15: styx.semantic.evaluate, -: 16: styx.semantic.statements, -: 17: styx.semantic.types, -: 18: styx.session, -: 19: styx.symbol, -: 20: styx.token, -: 21: ; -: 22: -: 23:/// Following symbolization, entry point to run the semantic checks. -: 24:function declarationSemantic(Declaration* node; Scope* scope = null) -: 25:{ 8725: 26: var auto ds = DeclarationsSemantics.create(scope ? node.scope); 8725: 27: ds.visitDeclaration(node); 8725: 28:} -: 29: -: 30:/// Retrieve the source symbol or the source type of the provided `AliasDeclaration*` -: 31:function getAliasee(AliasDeclaration* node; Scope* scope; var Type* resultType; var Symbol* resultSym) -: 32:{ 1150: 33: if node.progress == SemanticProgress.pending do 55: 34: declarationSemantic(node, scope); // node.scope 1150: 35: if node.type && node.type.progress == SemanticProgress.done do -: 36: { 368: 37: resultType = node.type; 368: 38: return; -: 39: } 782: 40: else do if node.sourceSymbol do -: 41: { 392: 42: resultSym = node.sourceSymbol; 392: 43: return; -: 44: } 390: 45: if node.symbol.recurseGuard != 0 do 3: 46: return; -: 47: -: 48: var Symbol* s; 387: 49: scope = scope.pushNested(); -: 50: 387: 51: if node.exp do -: 52: { -: 53: var TypeExpression* te; 140: 54: if (te = asTypeExp(node.exp)) do 33: 55: te.raw = false; 140: 56: scope.flags += ScopeFlag.isInInitializer; 140: 57: node.exp = expressionSemantic(node.exp, scope); 140: 58: scope.flags -= ScopeFlag.isInInitializer; 140: 59: if !te && node.exp.symbol do -: 60: { 99: 61: node.sourceSymbol = node.exp.symbol; 99: 62: resultSym = node.exp.symbol; 99: 63: scope = scope.pop(); 198: 64: if var auto ae = asApplyExp(node.exp) do 96: 65: node.sourceSymbol.astNode.asDeclaration().$protection = node.$protection; 99: 66: return; -: 67: } 41: 68: node.type = node.exp.type; -: 69: } -: 70: -: 71: // it is necessarily a type if not an identifier -: 72: // note that might change with the addition of tuples... 288: 73: var auto tid = asTypeIdentifier(node.type); 288: 74: if !tid || tid.genericArguments do -: 75: { 220: 76: ++node.symbol.recurseGuard; 220: 77: scope.flags += doSkipAdhocSema; 220: 78: scope.flags += ScopeFlag.isInInitializer; 220: 79: node.type = resolveType(node.type, scope); 220: 80: --node.symbol.recurseGuard; 220: 81: resultType = node.type; 220: 82: scope = scope.pop(); 220: 83: return; -: 84: } -: 85: // unit, VarDecl, FunctDecl etc. or type w/o modifiers -: 86: // dont do resolveType(), as that is really only designed to find Type -: 87: var bool strict; 68: 88: while tid do -: 89: { 93: 90: if !strict do -: 91: { 68: 92: foreach var auto we in scope.withSyms do 1: 93: if (s = we.searchSym.searchStrict(tid.identifier, node.startPos, scope.sym)) do 1: 94: break; 68: 95: s ?= scope.sym.searchWild(tid.identifier, node.startPos, scope.sym); -: 96: } 25: 97: else do s = scope.sym.searchStrict(tid.identifier, node.startPos, scope.sym); 93: 98: if s do -: 99: { 88: 100: checkDeprecated(tid, s.astNode, scope); 176: 101: if var auto ad = symToAliasDecl(s) do -: 102: { 14: 103: if ad.progress != SemanticProgress.done do 6: 104: declarationSemantic(ad, scope); 14: 105: if ad.progress != SemanticProgress.done do 3: 106: return; 11: 107: s = null; 11: 108: resultSym = null; 11: 109: resultType = null; 11: 110: getAliasee(ad, scope, resultType, resultSym); 11: 111: if !tid.next do 8: 112: return; 3: 113: if resultSym do 1: 114: s = resultSym; 2: 115: else do if resultType do 2: 116: s = resultType.asSymbol(); -: 117: } 148: 118: else do if var auto vd = symToVarDecl(s) do -: 119: { 20: 120: if const auto td = asTypeAggregate(vd.type) do 1: 121: s = td.declaration.symbol; -: 122: } -: 123: } 82: 124: if !s do -: 125: { 5: 126: resultSym = null; 5: 127: resultType = null; 5: 128: return; -: 129: } 77: 130: strict = true; 77: 131: scope.setSym(s); 77: 132: tid = tid.next; -: 133: } -: 134: 52: 135: if s do -: 136: { 104: 137: if var auto t = s.asType() do -: 138: { -: 139: // prefer func as symbol over func type 72: 140: if var auto tf = t.asTypeFunction() do -: 141: { 13: 142: if tf.declaration do -: 143: { 13: 144: node.sourceSymbol = s; 13: 145: resultSym = s; -: 146: } -: 147: } 23: 148: else do if !isTypeError(t) do -: 149: { 23: 150: node.type = t; 23: 151: resultType = t; -: 152: } -: 153: } -: 154: else do -: 155: { 16: 156: node.sourceSymbol = s; 16: 157: resultSym = s; -: 158: } -: 159: } 52: 160:} -: 161: -: 162:/** -: 163: * If the provided type is a TypeEnum or a TypeEnumSet then insert -: 164: * the matching enum to the provided scope's with expressions. -: 165: * -: 166: * Params: -: 167: * p = position where the pseudo `with(EnumName)` is located -: 168: * t = type to inspect -: 169: * sc = the affected scope -: 170: */ -: 171:function tryAddScopedEnum(var Position p; Type* t; Scope* sc) -: 172:{ 32098: 173: var auto te = asTypeEnum(t); 32098: 174: var auto tes = asTypeEnumSet(t); 32098: 175: te = tes ? tes.declaration.asTypeDeclared.asTypeEnum() else te; 32098: 176: if te && isEponymous !in te.declaration.flags do -: 177: { 1595: 178: sc.enumSym = (new WithExpression).create( -: 179: (new IdentExpression).create(p, te.declaration.name, te, te.declaration.symbol), -: 180: te.declaration.symbol -: 181: ); -: 182: } 32098: 183:} -: 184: -: 185:protection (private) -: 186: -: 187:@final class DeclarationsSemantics : AstVisitor -: 188:{ -: 189: var Scope* scope; -: 190: -: 191: @constructor function create(const Scope* scope) -: 192: { 8725: 193: this.scope = scope; 8725: 194: } -: 195: -: 196: function checkAtDeprecated(Declaration* node) -: 197: { 24463: 198: var auto a = node.getAtDeprecated(); 24463: 199: if !a || !a.arguments.length do 24460: 200: return; 3: 201: scope = scope.pushNested(); 3: 202: a.arguments[0] = expressionSemantic(a.arguments[0], scope); 3: 203: scope = scope.pop(); 6: 204: if var auto e = evaluate(a.arguments[0]) do 1: 205: a.arguments[0] = e; 3: 206: var auto se = asStringExp(a.arguments[0]); 3: 207: if !se do -: 208: { 1: 209: error(scope.filename, a.arguments[0].startPos, "expression `%s` does not evaluate to a string literal", format(a.arguments[0]).ptr); 1: 210: a.arguments[0].free(); 1: 211: a.arguments[0] = null; 1: 212: a.arguments.length = 0; -: 213: } 3: 214: } -: 215: -: 216: function checkAtFinal(Declaration* node) -: 217: { 24463: 218: if !node.getAtFinal() do 23468: 219: return; 995: 220: switch node.kind do -: 221: { 994: 222: on TokenType.$function, TokenType.$class, TokenType.$enum, TokenType.$alias do {} 1: 223: else do error(scope.filename, node.startPos, "only `function`, `class`, or `enum` can be `@final`"); -: 224: } 995: 225: } -: 226: -: 227: function checkAtForeign(Declaration* node) -: 228: { 24463: 229: if !node.getAtForeign() do 23836: 230: return; 627: 231: if node.genericParameters do 1: 232: return error(scope.filename, node.startPos, "`@foreign` declarations cannot be generic"); 626: 233: const auto isFunc = node.kind == $function; 626: 234: const auto isVar = node.kind == $var; 626: 235: const auto isAgg = node.kind == $struct || node.kind == $union; 626: 236: if !(isFunc || isAgg ||isVar) do 1: 237: return error(scope.filename, node.startPos, "only `function`, `struct` and `union`, can be `@foreign`"); 625: 238: var auto sd = node.asStructDeclaration(); 625: 239: var auto ud = node.asUnionDeclaration(); 625: 240: var auto fd = node.asFunctionDeclaration(); 625: 241: var auto vd = node.asVariableDeclaration(); 625: 242: if !vd && (sd?.body || ud?.body || fd?.body) do 1: 243: return error(scope.filename, node.startPos, "`@foreign` declarations must not have a body"); 624: 244: if vd?.initializer do 1: 245: return error(scope.filename, node.startPos, "`@foreign` variable must not have initializer"); 626: 246: if sd do sd.linkageKind = foreign; 623: 247: if ud do ud.linkageKind = foreign; 623: 248: if fd do -: 249: { 617: 250: fd.linkageKind = foreign; 617: 251: fd.stc += $static; -: 252: } 626: 253: if vd do vd.linkageKind = foreign; 623: 254: } -: 255: -: 256: function checkAtTLS(Declaration* node) -: 257: { 24463: 258: if !node.getAtTLS() do 24459: 259: return; 4: 260: if node.kind != $var do 1: 261: error(scope.filename, node.startPos, "only variables can be `@tls`"); 4: 262: } -: 263: -: 264: function checkAtNoinit(Declaration* node) -: 265: { 24463: 266: if !node.getAtNoinit() do 24397: 267: return; 66: 268: if node.kind != $var do 1: 269: error(scope.filename, node.startPos, "only variables can be `@noinit`"); 66: 270: } -: 271: -: 272: function checkAtFuncOnlyAttribs(Declaration* node) -: 273: { 24463: 274: if node.kind == $function do 5935: 275: return; -: 276: var s8* e; 18528: 277: if node.getAtAsm() do 1: 278: e = "only `function` can be `@asm`"; 18528: 279: if node.getAtAbstract() do 1: 280: e = "only `function` can be `@abstract`"; 18528: 281: if node.getAtConstructor() do 1: 282: e = "only `function` can be `@constructor`"; 18528: 283: if node.getAtDestructor() do 1: 284: e = "only `function` can be `@destructor`"; 18528: 285: if node.getAtInline() do 1: 286: e = "only `function` can be `@inline`"; 18528: 287: if node.getAtLLVM() do 1: 288: e = "only `function` can be `@LLVM`"; 18528: 289: if node.getAtNoopt() do 1: 290: e = "only `function` can be `@noopt`"; 18528: 291: if node.getAtNoReturn() do 1: 292: e = "only `function` can be `@noreturn`"; 18528: 293: if node.getAtOverload() do 1: 294: e = "only `function` can be `@overload`"; 18528: 295: if node.getAtOverride() do 1: 296: e = "only `function` can be `@override`"; 18528: 297: if node.getAtUnittest() do 1: 298: e = "only `function` can be `@unittest`"; 18528: 299: if node.getAtVirtual() do 1: 300: e = "only `function` can be `@virtual`"; 18528: 301: if e do 12: 302: error(scope.filename, node.startPos, e); 18528: 303: } -: 304: -: 305: function checkAtOperator(Declaration* node) -: 306: { 24463: 307: if !node.getAtOperator() do 24318: 308: return; 145: 309: var auto fd = symToFuncDecl(node.symbol); 145: 310: var auto od = symToOverDecl(node.symbol); 145: 311: const auto isCustomType = (fd || od) && node.symbol.parent.kind in aggregateKinds; 145: 312: if !isCustomType do 1: 313: error(scope.filename, node.startPos, "`@operator` is only supported by functions and overloads declared in `class`, `struct` and `union`"); 145: 314: } -: 315: -: 316: function checkAtReturnCtor(Declaration* node) -: 317: { 23848: 318: if !node.getAtReturn() do 23821: 319: return; 27: 320: var auto vd = node:VariableDeclaration*; 27: 321: if vd do -: 322: { 21: 323: vd.flags += skipManagment; 21: 324: return; -: 325: } 6: 326: var auto fd = node.asFunctionDeclaration(); 6: 327: var auto s = fd ? fd.symbol.parentAggregate() else null; 6: 328: var auto ad = s ? s.asType().asTypeAggregate().declaration else null; 6: 329: if !(fd && ad && !fd.isStatic()) do 1: 330: return error(scope.filename, node.startPos, "only variables or non-static member function can be `@return`"); 5: 331: if ad.asTypeDeclared.resolved() != fd.returnType.resolved() do 1: 332: return error(scope.filename, node.startPos, "`@return` function for a `%s` must also return a `%s`", format(ad).ptr, format(ad).ptr); 4: 333: if ad.returnCtor do 1: 334: return error(scope.filename, node.startPos, "only a single `@return` function is allowed"); 3: 335: if fd.parameters.length != 1 do 1: 336: return error(scope.filename, node.startPos, "`@return` function must not have parameters"); 2: 337: ad.returnCtor = fd; 2: 338: } -: 339: -: 340: function checkEscapesInGenericArgs(Declaration* node) -: 341: { 24463: 342: if !node.genericParameters || !node.genericParameters.applied() do 24237: 343: return; -: 344: //var bool hasFuncReadingEscape; 226: 345: foreach var auto gp in node.genericParameters.parameters do -: 346: { 369: 347: var auto ae = gp.appliedExp; 369: 348: if !ae do 118: 349: continue; 251: 350: var auto fd = symToFuncDecl(ae.symbol); 251: 351: if !fd || isReadingEscapes !in fd.flags do 243: 352: continue; -: 353: // dont allow a function reading escapes as aggregate generic argument 8: 354: if node.kind != $function do 1: 355: return error(scope.filename, node.startPos, "function `%s` cannot be used to apply generic `%s` because it requires escapes from a function frame", format(ae).ptr, format(node.baseGeneric).ptr); -: 356: -: 357: /* currently -: 358: 1. if a generic function requires a generic param that's a nested func then they use the same escape -: 359: 2. if a generic function requires two generic params that are nested funcs they both use the same escape -: 360: -: 361: // dont allow a function reading escapes as function generic argument -: 362: // and if that function already reads other escapes -: 363: var auto fdg = *((&node):FunctionDeclaration**); -: 364: if isReadingEscapes in fdg.flags do -: 365: return error(scope.filename, node.startPos, "function `%s` cannot be used to apply function `%s` because `%s` already requires escapes from a parent frame", format(ae).ptr, node.name.text().ptr); -: 366: -: 367: // dont allow a second function reading escapes if one was already passed -: 368: if hasFuncReadingEscape do -: 369: return error(scope.filename, node.startPos, "function `%s` cannot be used to apply function `%s` because another generic argument already requires escapes from a parent frame", format(ae).ptr, node.name.text().ptr); -: 370: hasFuncReadingEscape = true; -: 371: */ -: 372: } 225: 373: } -: 374: -: 375: function hasCircularInheritance(AggregateDeclaration* toCheck; AggregateDeclaration* inherited): bool -: 376: { 849: 377: if inherited.symbol.recurseGuard do 1: 378: return false; 848: 379: inherited.symbol.recurseGuard++; 848: 380: foreach var auto b in inherited.inheritanceList do -: 381: { 523: 382: var auto tc = b.asTypeClass(); 523: 383: if tc && tc.declaration == toCheck do -: 384: { 2: 385: error(scope.filename, toCheck.startPos, "circular inheritance between `%s` and `%s`", toCheck.name.text().ptr, inherited.name.text().ptr); 2: 386: inherited.symbol.recurseGuard--; 2: 387: return true; -: 388: } 521: 389: if tc && hasCircularInheritance(toCheck, tc.declaration) do -: 390: { 1: 391: inherited.symbol.recurseGuard--; 1: 392: return true; -: 393: } -: 394: } 845: 395: inherited.symbol.recurseGuard--; 845: 396: return false; -: 397: } -: 398: -: 399: static function propagateAtOperatorFlags(AggregateDeclaration* ad; Attribute* atOperator) -: 400: { 5369: 401: if ad && atOperator do -: 402: { 143: 403: ad.hasOpOvers = true; 143: 404: if atOperator.arguments[0].operator == id do 4: 405: ad.canResolveIdentifiers = true; -: 406: } 5369: 407: } -: 408: -: 409: static function setMembersIndexes(AggregateDeclaration* node) -: 410: { 1164: 411: if node.numMembers do 64: 412: return; -: 413: var s32 memberIndex; -: 414: //printf("%s\n", node.name.text().ptr); 1100: 415: if node.kind == $class do -: 416: { 476: 417: memberIndex = 1; // vtbl 476: 418: if node.inheritanceList.length do 664: 419: if var auto tc = asTypeClass(node.inheritanceList[0]) do -: 420: { 329: 421: if tc.declaration.progress == running do 10: 422: setMembersIndexes(tc.declaration); 329: 423: memberIndex = tc.declaration.numMembers; -: 424: } -: 425: } 2200: 426: if var auto b = node.body do 1093: 427: foreach var auto d in b.items do 3563: 428: if !d.isStatic() do 5966: 429: if var auto vd = asVariableDeclaration(d) do -: 430: { 831: 431: vd.index = memberIndex++; -: 432: //printf("%s.index=%d\n", vd.name.text().ptr, vd.index); -: 433: //fflush(0); -: 434: } 1100: 435: node.numMembers = memberIndex; -: 436: //printf("\n"); 1100: 437: } -: 438: -: 439: function visitAggregateMembers(AggregateDeclaration* node; const bool funcPass) -: 440: { 1916: 441: if !node.body do 14: 442: return; 1902: 443: foreach const auto d in node.body.items do -: 444: { 6604: 445: if funcPass && d.kind == TokenType.$function do 2113: 446: visitDeclaration(d); 4491: 447: else do if !funcPass && d.kind != TokenType.$function do 1189: 448: visitDeclaration(d); -: 449: } 1902: 450: } -: 451: -: 452: @override function visitAliasDeclaration(AliasDeclaration* node) -: 453: { 410: 454: if node.progress == done do 58: 455: return; 352: 456: if node.progress == running do 3: 457: return error(scope.filename, node.startPos, "circular reference to `%s`", format(node).ptr); 349: 458: node.progress = running; -: 459: var Symbol* s; -: 460: var Type* t; 349: 461: getAliasee(node, scope, t, s); 349: 462: if node.getAtFinal() do -: 463: { 2: 464: var auto cd = node.exp && s && s.kind == $class ? *((&s.astNode):ClassDeclaration**) else null; 2: 465: if cd && cd.genericParameters.applied() do -: 466: { 1: 467: cd.attributes ?= (new Attributes).create(node.startPos); 1: 468: cd.attributes.noArgAttributes += atFinal; -: 469: } 1: 470: else do error(scope.filename, node.startPos, "`@final alias` only allowed on applications of generic classes"); -: 471: } 349: 472: if (!s && !t) || (t && isTypeError(t)) do 32: 473: error(scope.filename, node.startPos, "cannot solve the source symbol of `%s`", format(node).ptr); 349: 474: node.progress = done; 349: 475: } -: 476: -: 477: @override function visitAttribute(Attribute* node) -: 478: { 1553: 479: const auto isAtOp = node.identifier.iptr() == operatorToken().iptr(); 1553: 480: const auto isAtOv = node.identifier.isTok:[$overload](); 1553: 481: const auto isAtAsm = node.identifier.isTok:[$asm](); 1553: 482: foreach var auto e in node.arguments do -: 483: { -: 484: // `@overload` and `@operator` and `@asm` arguments dont need to be semantically correct 256: 485: if isAtOv || isAtAsm do 13: 486: continue; 243: 487: if isAtOp do 156: 488: continue e = expToMacroOperator(e); -: 489: 87: 490: scope = scope.pushNested(); 87: 491: e = expressionSemantic(e, scope); 87: 492: scope = scope.pop(); 174: 493: if var auto ev = evaluate(e) do 73: 494: e = ev; -: 495: } 1553: 496: } -: 497: -: 498: @override function visitBlockStatement(const BlockStatement* node) -: 499: { -: 500: assert(0); -: 501: } -: 502: -: 503: @override function visitClassDeclaration(ClassDeclaration* node) -: 504: { 646: 505: if node.isGeneric() do 24: 506: return; 622: 507: if node.progress == SemanticProgress.done do 143: 508: return; 479: 509: if node.progress == SemanticProgress.running do 3: 510: return error(scope.filename, node.startPos, "circular reference to `%s`", format(node).ptr); 476: 511: node.progress = SemanticProgress.running; 476: 512: var auto old = scope; 476: 513: scope = node.scope; 476: 514: if session.hasRtl && !node.inheritanceList.length do -: 515: { 86: 516: const auto t = objectToken(); 86: 517: if node.name.iptr() != t.iptr() do 41: 518: node.inheritanceList ~= (new TypeIdentifier).create(t); -: 519: } 476: 520: foreach var auto b in node.inheritanceList do 335: 521: b = resolveType(b, scope); -: 522: var TypeClass* firstTypeClass; -: 523: var TypeClass* currentTypeClass; 476: 524: foreach (const auto i; var auto b) in node.inheritanceList do -: 525: { 335: 526: b = b.resolved(); 335: 527: currentTypeClass = b.asTypeClass(); 335: 528: var auto ctcDecl = currentTypeClass?.declaration; 335: 529: if ctcDecl do -: 530: { 335: 531: if ctcDecl.canResolveIdentifiers do node.canResolveIdentifiers = true; 333: 532: if ctcDecl.getAtFinal() do -: 533: { 2: 534: error(scope.filename, node.startPos, "`%s` cannot inherit of `%s` because it is annotated `@final`", -: 535: format(node).ptr, format(ctcDecl).ptr); -: 536: } -: 537: } -: 538: // first item must be a class 335: 539: if i == 0 do -: 540: { 332: 541: if (firstTypeClass = currentTypeClass) do 331: 542: node.vtable = firstTypeClass.declaration.vtable.dup; -: 543: } 3: 544: else do if currentTypeClass && firstTypeClass do -: 545: { 2: 546: error(scope.filename, node.startPos, "classes can only inherit from a single class and not both `%s` and `%s`", format(firstTypeClass).ptr, format(b).ptr); -: 547: } -: 548: // self inheritance impossible 335: 549: if currentTypeClass?.declaration == node do -: 550: { 2: 551: break error(scope.filename, node.startPos, "`%s` inherits from itself", format(node).ptr); -: 552: } -: 553: // circular inheritance 333: 554: if firstTypeClass && currentTypeClass && hasCircularInheritance(node, ctcDecl) do -: 555: { 2: 556: return; -: 557: } -: 558: // duplicated inheritance : assume typo so error 331: 559: foreach (const auto i1; var auto b1) in node.inheritanceList do -: 560: { 338: 561: b1 = b1.resolved(); 338: 562: if i == i1 do 330: 563: continue; 8: 564: if b == b1 do -: 565: { 2: 566: error(scope.filename, node.startPos, "`%s` inherits at least twice of `%s`", format(node).ptr, format(b).ptr); 2: 567: break; -: 568: } -: 569: } 331: 570: if ctcDecl && ctcDecl.hasOpOvers do 263: 571: node.hasOpOvers = true; -: 572: } 474: 573: if node.getAtFinal() && node.body do 161: 574: foreach var auto d in node.body.items do -: 575: { 1315: 576: var auto fd = asFunctionDeclaration(d); -: 577: // @final makes only sense if -: 578: // - @virtual @override : means that fd.attributes exists -: 579: // - not static 1315: 580: if !fd || !fd.attributes || fd.isStatic() || fd.getAtFinal() || !(fd.getAtVirtual() || fd.getAtOverride()) do 582: 581: continue; 733: 582: fd.attributes.noArgAttributes += atFinal; -: 583: } 483: 584: if node.genericParameters do visitGenericParameters(node.genericParameters); -: 585: -: 586: // do function headers first, this is because member variables -: 587: // can launch the sema of a derived class so the base vtbl must be ready 474: 588: visitAggregateMembers(node, true); -: 589: 474: 590: visitAggregateMembers(node, false); 474: 591: node.progress = SemanticProgress.done; 474: 592: setMembersIndexes(node); 474: 593: scope = old; 474: 594: if node.vtableVar do -: 595: { 473: 596: var auto ie = (new IntegerExpression).create(node.vtableVar.startPos, null, node.vtable.length + 1, TypeUSize()); 473: 597: var auto tp1 = (new TypePointer).create(TypeU8.instance()); 473: 598: var auto ts1 = (new TypeStaticArray).create(tp1, ie); 473: 599: var auto tp2 = (new TypePointer).create(ts1); 473: 600: node.vtableVar.type = tp2; -: 601: } 474: 602: } -: 603: -: 604: @override function visitDeclaration(Declaration* node) -: 605: { 27782: 606: if node.attributes do visitAttributes(node.attributes); 24463: 607: checkAtFinal(node); 24463: 608: checkAtForeign(node); 24463: 609: checkAtFuncOnlyAttribs(node); 24463: 610: checkAtOperator(node); 24463: 611: checkAtTLS(node); 24463: 612: checkAtNoinit(node); 24463: 613: checkAtDeprecated(node); -: 614: // need partial info retrieved during sema 24463: 615: if node.kind != $function do 18528: 616: checkAtReturnCtor(node); 24463: 617: super(node); 24463: 618: checkEscapesInGenericArgs(node); 24463: 619: setLinkageName(node); 24463: 620: } -: 621: -: 622: @override function visitEnumDeclaration(EnumDeclaration* node) -: 623: { 464: 624: if node.progress == done do 33: 625: return; 431: 626: if node.progress == running do -: 627: { 5: 628: node.type = TypeError.instance(); 5: 629: return error(scope.filename, node.startPos, "circular reference to `%s`", format(node).ptr); -: 630: } 426: 631: node.progress = SemanticProgress.running; -: 632: -: 633: // check non-auto type 426: 634: node.type ?= TypeU32.instance(); 426: 635: const auto isAuto = isTypeAuto(node.type); 426: 636: if !isAuto do -: 637: { 422: 638: scope = scope.pushNested(); 422: 639: node.type = resolveType(node.type, scope); 422: 640: scope = scope.pop(); -: 641: } -: 642: var TypeEnum* base; 426: 643: if node.type do -: 644: { 426: 645: if !isAuto && !node.type.resolved().isIntegral() && !isTypeBool(node.type) do -: 646: { 1: 647: error(scope.filename, node.startPos, "enum `%s` type must be integral and not `%s`", node.name.text().ptr, format(node.type).ptr); 1: 648: node.type = TypeError.instance(); 1: 649: return; -: 650: } 850: 651: if var auto te = node.type.asTypeEnum() do -: 652: { 17: 653: if te.declaration == node do -: 654: { 1: 655: node.type = TypeError.instance(); 1: 656: return error(scope.filename, node.startPos, "enum `%s` cannot extend itself", node.name.text().ptr); -: 657: } 16: 658: if te.declaration.progress != done do 3: 659: declarationSemantic(te.declaration, te.declaration.scope); 16: 660: if isTypeError(te.declaration.type) do -: 661: { 3: 662: node.type = TypeError.instance(); 3: 663: return error(scope.filename, node.startPos, "enum `%s` cannot extend an erroneous enum", node.name.text().ptr); -: 664: } 13: 665: if te.declaration.getAtFinal() do 1: 666: error(scope.filename, node.startPos, "enum `%s` cannot be extended because it is `@final`", te.declaration.name.text().ptr); 13: 667: base = te; 13: 668: node.base = te; -: 669: } -: 670: } -: 671: -: 672: // make sure explicit members values are int literals 421: 673: foreach const auto em in node.members do -: 674: { 989: 675: if em.attributes do visitDeclaration(em); 989: 676: if !em.value do 622: 677: continue; 367: 678: em.value = expressionSemantic(em.value, scope.pushNested()); 367: 679: if em.value.symbol && em.value.symbol == em.symbol do -: 680: { 1: 681: node.type = TypeError.instance(); 1: 682: return error(scope.filename, node.startPos, "circular reference to member `%s`", format(em).ptr); -: 683: } 366: 684: if em.value.type.resolved().isIntegral() do 630: 685: if var auto e = evaluate(em.value) do 315: 686: em.value = e; 366: 687: if asIntegerExp(em.value) == null do -: 688: { 2: 689: node.type = TypeError.instance(); 2: 690: return error(scope.filename, em.startPos, "enum member `%s` has a value that could not be folded to a constant integer", em.name.text().ptr); -: 691: } -: 692: } -: 693: -: 694: // create implicit member values and cache if it's usable as TypeEnumSet 418: 695: var auto ordered = true; 418: 696: var auto prev = base ? base.declaration.max.asIntegerExp() else null; 418: 697: foreach const auto em in node.members do -: 698: { 985: 699: if !em.value do -: 700: { 621: 701: em.value = prev = (new IntegerExpression).create(em.startPos, null, prev ? (prev.value + 1) else 0, TypeU64.instance()); -: 702: } -: 703: else do -: 704: { 364: 705: const auto curr = asIntegerExp(em.value); 364: 706: if !prev || prev.value != curr.value - 1 do 339: 707: ordered = false; 364: 708: prev = curr; -: 709: } 985: 710: if !isAuto do -: 711: { 1962: 712: if var auto econv = implicitConvTo(em.value, getEnumRootType(node), scope) do 1954: 713: if var auto e = evaluate(em.value = econv) do 977: 714: em.value = e; 981: 715: prev = asIntegerExp(em.value); -: 716: } -: 717: } -: 718: -: 719: // check for value uniqueness -: 720: var u64 max; 418: 721: var auto baseMax = base ? base.declaration.max.asIntegerExp() else null; 418: 722: foreach (const auto i; var auto mi) in node.members do 980: 723: foreach (const auto j; var auto mj) in node.members[i .. $] do -: 724: { 16189: 725: var auto ie1 = getIntLiteral(mi.value); 16189: 726: if baseMax && (ie1.value <= baseMax.value) do -: 727: { 1: 728: node.type = TypeError.instance(); 1: 729: return error(scope.filename, mi.startPos, "enum member `%s` value must be greater than the max base enum member", mi.name.text().ptr); -: 730: } 16188: 731: if ie1 && ie1.value > max do 833: 732: max = ie1.value; 16188: 733: if j == 0 do 979: 734: continue; -: 735: 15209: 736: if ie1.value == getIntLiteral(mj.value).value do -: 737: { 3: 738: node.type = TypeError.instance(); 3: 739: return error(scope.filename, mi.startPos, "enum member `%s` and `%s` have the same value", -: 740: mi.name.text().ptr, mj.name.text().ptr); -: 741: } -: 742: } -: 743: -: 744: // cache .min and .max 414: 745: var auto mini = base ? base.declaration.min.getIntLiteral() else null; -: 746: var IntegerExpression* maxi; 414: 747: if !node.type.isSigned() do 308: 748: foreach var auto em in node.members do -: 749: { 852: 750: var auto ie = getIntLiteral(em.value); 852: 751: mini = (!mini || ie.value <= mini.value) ? ie else mini; 852: 752: maxi = (!maxi || ie.value >= maxi.value) ? ie else maxi; -: 753: } 106: 754: else do foreach var auto em in node.members do -: 755: { 123: 756: var auto ie = getIntLiteral(em.value); 123: 757: mini = (!mini || ie.value:s64 <= mini.value:s64) ? ie else mini; 123: 758: maxi = (!maxi || ie.value:s64 >= maxi.value:s64) ? ie else maxi; -: 759: } 414: 760: node.min = mini; 414: 761: node.max = maxi; 414: 762: if isAuto do -: 763: { 4: 764: const auto t = integerTypeFor(max); 4: 765: node.type = t; 4: 766: foreach var auto em in node.members do 4: 767: em.value.type = t; -: 768: } -: 769: 414: 770: node.asTypeDeclared.size = node.type.resolved().size; 414: 771: node.flags[isOrdered] = ordered; 414: 772: node.flags[hasRoomForSet] = node.members.length <= node.asTypeDeclared.size; 414: 773: node.flags[inValueRange] = max <= node.asTypeDeclared.size - 1; 414: 774: node.progress = done; 414: 775: } -: 776: -: 777: @override function visitEnumMember(const EnumMember* node) -: 778: { -: 779: assert(0); -: 780: } -: 781: -: 782: @override function visitExpression(const Expression* node) -: 783: { -: 784: assert(0); -: 785: } -: 786: -: 787: @override function visitExpressionAlias(ExpressionAlias* node) -: 788: { 17: 789: if node.symbol.parent.kind in unitKinds do 1: 790: error(scope.filename, node.startPos, "expression aliases are not allowed at the unit scope"); 17: 791: } -: 792: -: 793: @override function visitFunctionDeclaration(FunctionDeclaration* node) -: 794: { 5645: 795: var auto ad = symToAggrDecl(node.symbol.parent); 5645: 796: if node.isGeneric() do -: 797: { 218: 798: if node.getAtVirtual() do 1: 799: error(scope.filename, node.startPos, "generic functions cant `@virtual`"); 218: 800: if ad && node.getAtOperator() do 1: 801: ad.hasOpOvers = true; 218: 802: return; -: 803: } 5427: 804: if ad && ad.progress == pending do -: 805: { 3: 806: declarationSemantic(ad, ad.scope); 3: 807: return; -: 808: } 5424: 809: if node.progress == done do 101: 810: return; 5323: 811: if node.progress == running do 3: 812: return error(scope.filename, node.startPos, "circular reference to `%s`", format(node).ptr); 5320: 813: node.progress = SemanticProgress.running; -: 814: 5320: 815: if !ad && node.name && node.name.iptr() == mainToken().iptr() do 242: 816: node.linkageKind = LinkageKind.foreign; -: 817: -: 818: // https://gitlab.com/styx-lang/styx/-/issues/354 -: 819: // just like for parameters, to determine the function type, no need -: 820: // to run declsema of possibly return aggregate, the type exists since symbolize() -: 821: // and is enough to check for example that overridden funcs have the same type. 5320: 822: var auto retSc = node.genericParameters ? node.scope else scope; 7489: 823: if ad do retSc.flags += ScopeFlag.doSkipAdhocSema; 5320: 824: node.returnType = resolveType(node.returnType, retSc); 7489: 825: if ad do retSc.flags -= ScopeFlag.doSkipAdhocSema; 5320: 826: node.virtualIndex = -1; 5320: 827: checkAtReturnCtor(node); -: 828: 5320: 829: const auto parentClass = ad ? ad.asTypeDeclared.asTypeClass() else null; 5320: 830: const auto isVariadic = isCeeVariadic in node.flags; 5320: 831: const auto isStatic = node.isStatic(); 5320: 832: const auto isMemberFunc = node.parameters.length && node.parameters[0].name == thisToken() && (isEscape !in node.parameters[0].flags); 5320: 833: const auto isUnitLevel = node.symbol.parent.kind in unitKinds; -: 834: 5320: 835: if !isStatic && scope.func do 194: 836: node.flags += FunctionFlag.isNested; 5320: 837: if isStatic && isMemberFunc do 1: 838: error(scope.filename, node.startPos, "member functions cannot be `static`"); -: 839: 5320: 840: var auto old = scope; 5320: 841: scope = node.scope; 5320: 842: node.symbol.recurseGuard++; 5452: 843: if node.genericParameters do visitGenericParameters(node.genericParameters); 5320: 844: foreach (const auto i; const auto vd) in node.parameters do -: 845: { 7490: 846: vd.index = i:s32; 7490: 847: visitDeclaration(vd); -: 848: } 5320: 849: node.symbol.recurseGuard--; 5320: 850: scope = old; -: 851: 5320: 852: var auto returnType = node.returnType.resolved(); 5320: 853: if !node.body && isTypeAuto(returnType) do -: 854: { 3: 855: var s8* msg = node.asmBody ? "cannot replace `auto` return type from an `asm` body`" -: 856: else "body-less functions and function types cannot have `auto` as return type"; 3: 857: error(scope.filename, node.startPos, msg); -: 858: } 5320: 859: if returnType.kind == tkSlice do 1: 860: error(scope.filename, node.startPos, "cannot return `%s` because it is a slice", returnType.format().ptr); 5320: 861: node.asTypeDeclared = resolveType(node.asTypeDeclared, node.scope); -: 862: 5320: 863: const auto atVirt = node.getAtVirtual(); 5320: 864: const auto atOver = node.getAtOverride(); 5320: 865: const auto atAbstract = node.getAtAbstract(); 5320: 866: const auto atFinal = node.getAtFinal(); 5320: 867: const auto atOperator = node.getAtOperator(); -: 868: 5320: 869: propagateAtOperatorFlags(ad, atOperator); 5320: 870: if atAbstract do -: 871: { -: 872: var s8* e; 11: 873: if !atVirt do 2: 874: e = "`@abstract` functions must also be `@virtual`"; 9: 875: else do if atOver do 1: 876: e = "only the base definition can be `@abstract`"; 8: 877: else do if node.body do 1: 878: e = "`@abstract` functions cant have bodies"; 7: 879: else do if atFinal do 1: 880: e = "`@abstract` functions cannot be `@final`"; 11: 881: if e do 5: 882: error(scope.filename, node.startPos, e); 11: 883: node.flags += isAbstract; -: 884: } 5320: 885: if atVirt || atOver do -: 886: { -: 887: var s8* e; 1147: 888: if node.symbol.parent.kind != SymbolKind.$class do -: 889: { 2: 890: node.progress = SemanticProgress.done; 2: 891: return error(scope.filename, node.startPos, "virtual functions can only be declared in classes and interfaces"); -: 892: } 1145: 893: else do if isStatic do 1: 894: e = "virtual functions cannot be `static`"; 1144: 895: else do if atVirt && atOver do 2: 896: e = "cannot declare and override a virtual functions at the same time"; 1142: 897: else do if !node.body && !atAbstract do 1: 898: e = "virtual functions must define a body"; 1145: 899: if e do 4: 900: error(scope.filename, node.startPos, e); 1145: 901: node.flags += FunctionFlag.isVirtual; 1145: 902: if atFinal do 750: 903: node.flags += FunctionFlag.isFinal; 1145: 904: if atVirt do -: 905: { 289: 906: node.virtualIndex = ad.vtable.length:s32; 289: 907: ad.vtable ~= node; -: 908: } 856: 909: else do foreach const auto fd in ad.vtable do 39729: 910: if fd.name.iptr() == node.name.iptr() do -: 911: { 854: 912: if isTypeError(node.symbol.asType()) || !node.symbol.asType().asTypeFunction().isEqualEx(fd.symbol.asType(), true, false) do 2: 913: error(scope.filename, node.startPos, "overridden function has not the same type as the base declaration"); 852: 914: else do if FunctionFlag.isFinal in fd.flags do 2: 915: error(scope.filename, node.startPos, "cannot override `@final function`"); 854: 916: node.virtualIndex = fd.virtualIndex; 1708: 917: if var auto fdAtOp = fd.getAtOperator() do -: 918: { -: 919: // note: will lead to double-free 21: 920: if atOperator do atOperator.arguments ~= fdAtOp.arguments; 17: 921: else do node.attributes.atOperator = fdAtOp; 19: 922: ad.hasOpOvers = true; 19: 923: if fdAtOp.arguments[0].operator == id do 1: 924: ad.canResolveIdentifiers = true; -: 925: } 854: 926: if fd.getAtDestructor() do 7: 927: node.attributes.noArgAttributes += atDestructor; 854: 928: break ad.vtable[node.virtualIndex] = node; -: 929: } 1145: 930: if node.virtualIndex == -1 && atOver do -: 931: { 2: 932: node.progress = SemanticProgress.done; 2: 933: return error(scope.filename, node.startPos, "cannot override a non virtual function"); -: 934: } -: 935: //printf("%s.%s virtual index : %d\n", ad.name.text().ptr, node.name.text().ptr, node.virtualIndex); -: 936: } 5316: 937: if !atOver && !atVirt do -: 938: { 4173: 939: if parentClass do 384: 940: foreach var auto fd in ad.vtable do 15388: 941: if fd.name.iptr() == node.name.iptr() do 1: 942: break error(scope.filename, node.startPos, "cannot redeclare `@virtual` function `%s` without `@override`", node.name.text().ptr); 4173: 943: if atFinal do 1: 944: error(scope.filename, node.startPos, "`@final` can only be used on `@virtual` or `@override` functions`"); -: 945: } 10632: 946: if var auto a = node.getAtLLVM() do -: 947: { -: 948: var s8* e; 27: 949: if !isUnitLevel do 1: 950: e = "`@LLVM` functions must be static and declared in the unit scope"; 27: 951: if node.body do 1: 952: e = "`@LLVM` functions must not have body"; 27: 953: if a.arguments.length && !asStringExp(a.arguments[0]) do 1: 954: e = "`@LLVM` parameter must be a string literal giving the instrinsic overload suffix"; 27: 955: if e do 3: 956: error(scope.filename, node.startPos, e); 27: 957: node.flags += FunctionFlag.isLLVM; -: 958: } 5316: 959: if node.getAtUnittest() do -: 960: { -: 961: var s8* e; 15: 962: if !isUnitLevel do 1: 963: e = "`@unittest` function must be static and declared in the unit scope"; 15: 964: if node.parameters.length || !isTypeVoid(node.returnType) do 2: 965: e = "`@unittest` functions must be of type `function();`"; 15: 966: if !node.body do 1: 967: e = "`@unittest` functions must define a body`"; 15: 968: if e do 4: 969: error(scope.filename, node.startPos, e); 15: 970: node.flags += FunctionFlag.isUnittest; -: 971: } 10632: 972: if var auto a = node.getAtInline() do -: 973: { 173: 974: if a.arguments do -: 975: { 124: 976: if var auto e = implicitConvTo(a.arguments[0], TypeBool.instance(), scope) do 61: 977: a.arguments[0] = e; 124: 978: if var auto e = evaluate(a.arguments[0]) do 61: 979: a.arguments[0] = e; 124: 980: if var auto be = asBoolExp(a.arguments[0]) do -: 981: { 73: 982: if be.value do node.flags += FunctionFlag.isInlineYes; -: 983: } 1: 984: else do error(scope.filename, node.startPos, "`@inline` parameter must be evaluable to a `bool` value"); -: 985: } 111: 986: else do node.flags += FunctionFlag.isInlineMaybe; -: 987: } 10632: 988: if var auto a = node.getAtAsm() do -: 989: { 3: 990: var auto badArg = true; 6: 991: if var auto id = asIdentExp(a.arguments[0]) do -: 992: { 2: 993: const auto i = id.identifier.iptr(); 2: 994: if i == asmFlavAttToken().iptr() do { /* default */ badArg = false; } 2: 995: else do if i == asmFlavIntelToken().iptr() do -: 996: { 4: 997: node.flags += isAsmIntel; badArg = false; 2: 998: if node.asmBody do 1: 999: error(scope.filename, node.startPos, "asm bodies only support the AT&T dialect"); -:1000: } -:1001: } 3:1002: if badArg do 1:1003: error(scope.filename, a.startPos, "invalid `@asm` argument, expected `att` or `intel`, not `%s`", format(a.arguments[0]).ptr); -:1004: } 5316:1005: const auto isCtor = node.getAtConstructor(); 5316:1006: const auto isDtor = node.getAtDestructor(); 5316:1007: if isCtor && isDtor do 1:1008: error(scope.filename, node.startPos, "function cannot be both `@constructor` and `@destructor`"); 5315:1009: else do if isCtor do -:1010: { 213:1011: if !isTypeVoid(node.returnType) do 1:1012: error(scope.filename, node.startPos, "`@constructor` functions have no return type"); 213:1013: if isStatic do -:1014: { 15:1015: if node.parameters.length do 1:1016: error(scope.filename, node.startPos, "static `@constructor` functions cant have parameters"); 15:1017: node.flags += FunctionFlag.isStaticCtor; -:1018: } -:1019: else do -:1020: { 198:1021: if !ad do error(scope.filename, node.startPos, "non static `@constructor` can only be declared in aggregates"); 198:1022: if ad && node.parameters.length == 1 do -:1023: { 71:1024: if ad.defaultCtor do 1:1025: error(scope.filename, node.startPos, "only one parameter-less constructor is allowed"); 71:1026: ad.defaultCtor = node; -:1027: } 198:1028: if parentClass && atVirt do -:1029: // with `new`, ctors can be virtual now 1:1030: error(scope.filename, node.startPos, "`@constructor` function cannot be virtual"); 198:1031: node.flags += FunctionFlag.isCtor; -:1032: } -:1033: } 5102:1034: else do if isDtor do -:1035: { 121:1036: if !isTypeVoid(node.returnType) do 1:1037: error(scope.filename, node.startPos, "static `@destructor` functions have no return type"); 121:1038: if isStatic do -:1039: { 61:1040: if node.parameters.length do 1:1041: error(scope.filename, node.startPos, "static `@destructor` functions cant have parameters"); 61:1042: node.flags += FunctionFlag.isStaticDtor; -:1043: } -:1044: else do -:1045: { 60:1046: if node.parameters.length > 1 do 1:1047: error(scope.filename, node.startPos, "`@destructor` functions cannot have parameters`"); 60:1048: if node.parameters.length == 1 do -:1049: { 117:1050: if !ad.defaultDtor do ad.defaultDtor = node; 1:1051: else do error(scope.filename, node.startPos, "only one member destructor is allowed"); -:1052: } 60:1053: node.flags += FunctionFlag.isDtor; -:1054: } -:1055: } -:1056: 5316:1057: var ssize firstInitialized = -1; 5316:1058: foreach (const auto i; var auto p) in node.parameters do 7442:1059: if p.initializer do 79:1060: break firstInitialized = i; 5316:1061: if firstInitialized != -1 do -:1062: { 79:1063: if isVariadic do 2:1064: error(scope.filename, node.startPos, "variadic functions cannot have parameters with a default value"); 77:1065: else do foreach var auto p in node.parameters[firstInitialized + 1 .. $] do 44:1066: if !p.initializer do 1:1067: error(scope.filename, node.startPos, "parameter `%s` must define a default value because it follows a parameter that specifies one", format(p).ptr); -:1068: } -:1069: 5316:1070: if node.asmBody do -:1071: { 7:1072: node.asmBody = expressionSemantic(node.asmBody, scope); 14:1073: if var auto e = evaluate(node.asmBody) do 1:1074: node.asmBody = e; 7:1075: if !asStringExp(node.asmBody) do 1:1076: error(scope.filename, node.asmBody.startPos, "asm body cannot be simplified to a string literal"); -:1077: } -:1078: 5316:1079: node.progress = SemanticProgress.done; 5316:1080: } -:1081: -:1082: @override function visitImportDeclaration(const ImportDeclaration* node) -:1083: { -:1084: // done in styx.semantic.imports 187:1085: } -:1086: -:1087: @override function visitOverloadDeclaration(OverloadDeclaration* node) -:1088: { 54:1089: if node.progress == SemanticProgress.done do 4:1090: return; 50:1091: if node.progress == SemanticProgress.running do 1:1092: return error(scope.filename, node.startPos, "circular reference to `%s`", format(node).ptr); 49:1093: node.progress = SemanticProgress.running; -:1094: 49:1095: propagateAtOperatorFlags(symToAggrDecl(node.symbol.parent), node.getAtOperator()); -:1096: var usize checkTypeFromIndex; 49:1097: if node.base do -:1098: { 4:1099: scope = scope.pushNested(); 4:1100: node.base = resolveType(node.base, scope); 4:1101: scope = scope.pop(); 8:1102: if var auto to = node.base.asTypeOverload() do -:1103: { 3:1104: if to.declaration.progress != SemanticProgress.done do 2:1105: declarationSemantic(to.declaration, to.declaration.scope); 3:1106: checkTypeFromIndex = to.declaration.members.length; 3:1107: node.members = to.declaration.members ~ node.members; -:1108: } 1:1109: else do error(scope.filename, node.startPos, "overload base type `%s` is not an overload", format(node.base).ptr); -:1110: } 49:1111: foreach var auto e in node.members do -:1112: { -:1113: // expsma on IdentExp actually does the fd analysis that -:1114: // is claimed to be avoided in next comment ? 110:1115: e = expressionSemantic(e, node.scope.pushNested()); -:1116: // Dont launch ad-hoc sema on fd because -:1117: // 1. the useful info already exists since the "symbolization" pass. -:1118: // 2. overloads are not emitted in objects -:1119: // 3. that can cause circular issues (https://gitlab.com/styx-lang/styx/-/issues/154) -:1120: // If required that will be launched when a CallExpression uses an overload member. 220:1121: if var auto fd = symToFuncDecl(e.symbol) do -:1122: { -:1123: // https://gitlab.com/styx-lang/styx/-/issues/{545|546|547} -:1124: // would require to delay verifications and to try to apply at the use site 107:1125: if fd.isGeneric() do 2:1126: error(scope.filename, e.startPos, "overload member `%s` cannot be an unapplied generic", format(e).ptr); -:1127: } 3:1128: else do error(scope.filename, e.startPos, "overload member `%s` does not resolve to a function", format(e).ptr); -:1129: } 49:1130: foreach (const auto i; var auto e0) in node.members[checkTypeFromIndex .. $] do -:1131: { 106:1132: var auto t0 = e0.symbol?.asType(); 106:1133: foreach var auto e1 in node.members[checkTypeFromIndex + i + 1 .. $] do -:1134: { 97:1135: var auto t1 = e1.symbol?.asType(); 97:1136: if !t0 || !t1 do 2:1137: continue; 95:1138: var auto tf0 = t0.asTypeFunction(); 95:1139: var auto tf1 = t1.asTypeFunction(); 95:1140: if !tf0 || !tf1 || !tf0.isEqualEx(tf1, false, true) do 92:1141: continue; 3:1142: error(scope.filename, e1.startPos, "the overload member `%s` has already the same parameters type", format(e0).ptr); -:1143: } -:1144: } 49:1145: node.progress = SemanticProgress.done; 49:1146: } -:1147: -:1148: @override function visitStatement(const Statement* node) -:1149: { -:1150: assert(0); -:1151: } -:1152: -:1153: @override function visitStaticAssertDeclaration(const StaticAssertDeclaration* node) -:1154: { 253:1155: statementSemantic(node.assertion, scope); 253:1156: } -:1157: -:1158: function visitStructOrUnion(AggregateDeclaration* node) -:1159: { 713:1160: if node.isGeneric() do 193:1161: return; 520:1162: if node.progress == SemanticProgress.done do 29:1163: return; 491:1164: if node.progress == SemanticProgress.running do 7:1165: return error(scope.filename, node.startPos, "circular reference to `%s`", format(node).ptr); 484:1166: node.progress = SemanticProgress.running; 484:1167: var auto old = scope; 484:1168: scope = node.scope; 564:1169: if node.genericParameters do visitGenericParameters(node.genericParameters); 484:1170: visitAggregateMembers(node, false); 484:1171: if node.inheritanceList.length do 7:1172: error(scope.filename, node.startPos, "`%s` cannot inherit", tokenString[node.kind].ptr); 484:1173: node.progress = SemanticProgress.done; 484:1174: visitAggregateMembers(node, true); 484:1175: scope = old; 484:1176: } -:1177: -:1178: @override function visitStructDeclaration(StructDeclaration* node) -:1179: { 680:1180: visitStructOrUnion(node); 680:1181: setMembersIndexes(node); 680:1182: } -:1183: -:1184: @override function visitUnionDeclaration(UnionDeclaration* node) -:1185: { 33:1186: visitStructOrUnion(node); 33:1187: } -:1188: -:1189: @override function visitVariableDeclaration(VariableDeclaration* node) -:1190: { 15066:1191: if node.progress == SemanticProgress.done do 32:1192: return; 15034:1193: if node.progress == SemanticProgress.running do 1:1194: return error(scope.filename, node.startPos, "circular reference to `%s`", format(node).ptr); 15033:1195: node.progress = SemanticProgress.running; -:1196: 15033:1197: scope = scope.pushNested(); 15033:1198: const auto isParam = node.isParameter; 15033:1199: if isParam do 7490:1200: scope.flags += ScopeFlag.doSkipAdhocSema; 15033:1201: scope.flags += ScopeFlag.isInInitializer; 15033:1202: node.type = resolveType(node.type, scope); 15033:1203: scope = scope.pop(); -:1204: 15033:1205: if isTypeAuto(node.type) do -:1206: { 2522:1207: if isParam do 1:1208: error(scope.filename, node.startPos, "function parameters cannot be of type `auto`"); 2521:1209: else do if !node.initializer && node.context != VariableDeclarationContext.localForeach && 2:1210: node.context != VariableDeclarationContext.localIf do -:1211: { 2:1212: error(scope.filename, node.startPos, "`%s` type cannot be resolved without initializer", node.name.text().ptr); -:1213: } -:1214: } -:1215: 15033:1216: const u8 isConst = node.isConst(); 15033:1217: const u8 isStatic = node.isStatic(); 15033:1218: const u8 isVar = node.isVar(); 15033:1219: const u8 count = isConst + isStatic + isVar; 15033:1220: if node.context == VariableDeclarationContext.default do -:1221: { 6443:1222: if count == 1 && isStatic do 1:1223: error(scope.filename, node.startPos, "variable `%s` must be `const` or `var` and not only `static`", node.name.text().ptr); 6442:1224: else do if isConst && isVar do 2:1225: error(scope.filename, node.startPos, "variable `%s` cannot be both `const var`", node.name.text().ptr); 6443:1226: if isConst && !node.initializer do 3:1227: error(scope.filename, node.startPos, "variable `%s` is `const` but has not initializer", node.name.text().ptr); -:1228: } 8590:1229: else do if node.context == VariableDeclarationContext.localForeach && node.initializer do -:1230: { 1:1231: error(scope.filename, node.startPos, "`foreach` variable initializers have no effects"); -:1232: } 15033:1233: if !isStatic && scope.func && !isParam do 6255:1234: scope.func.allocas ~= node; -:1235: -:1236: // if the decl is not static then is is a member and its size must really be known 15033:1237: if !isStatic do -:1238: { 14620:1239: var auto tp = asTypePointer(node.type); 14620:1240: var auto s = node.type.asSymbol(); 14620:1241: if !tp && s do -:1242: { 1182:1243: if var auto d = s.astNode.asDeclaration() do -:1244: { 591:1245: if d.progress != SemanticProgress.done do 13:1246: declarationSemantic(d, d.scope); -:1247: } -:1248: } -:1249: } -:1250: 15033:1251: var auto t = node.type.resolved(); 15033:1252: if node.initializer do -:1253: { 4302:1254: var auto ae = asArrayExp(node.initializer); 4302:1255: var auto old = scope; 4302:1256: scope = scope.pushNested(); 4302:1257: node.symbol.flagAsBeingInit(true); 4302:1258: scope.flags += ScopeFlag.isInInitializer; 4302:1259: tryAddScopedEnum(node.initializer.startPos, t, scope); 4302:1260: node.initializer = expressionSemantic(node.initializer, scope); 4302:1261: scope = old; 4302:1262: node.symbol.flagAsBeingInit(false); -:1263: -:1264: // `var auto a = [b]` has been rewritten `var auto a = __tmp = [b]` -:1265: // supress the temporary if the initializer has not been transformed -:1266: // in a slice or a RcArray (which require the temporary lvalue for .ptr and .length) 4302:1267: var auto tes = asTypeEnumSet(node.type); 4302:1268: var auto tsa = asTypeStaticArray(node.type); 4302:1269: if ae && ae.type && (tsa || tes || isTypeAuto(node.type) ) do 165:1270: node.initializer = ae; -:1271: 4302:1272: if isVar && node.isParameter && !node.initializer.isLvalue() do -:1273: { 1:1274: error(scope.filename, node.startPos, "default argument is not a lvalue but parameter `%s` is `var`", node.name.text().ptr); -:1275: } 4302:1276: if isStatic || (node.symbol.parent.kind in aggregateKinds) do -:1277: { 204:1278: if node.isUnionMember() do 2:1279: return error(scope.filename, node.startPos, "union members cannot declare an initializer"); 202:1280: if asIdentExp(node.initializer) do 14:1281: if var auto vd = symToVarDecl(node.initializer.symbol) do 4:1282: if vd.initializer?.isLiteral() do 1:1283: node.initializer = vd.initializer; 202:1284: if !node.initializer.canInitialize() do 66:1285: if var auto e = evaluate(node.initializer) do 10:1286: node.initializer = e; -:1287: } -:1288: -:1289: var bool wasAuto; 4300:1290: if isTypeAuto(node.type) do -:1291: { 2046:1292: wasAuto = true; 2046:1293: node.type = t = node.initializer.type.resolved(); -:1294: } 4300:1295: if !scope.func && (isStatic || (node.symbol.parent.kind in aggregateKinds)) do 151:1296: if !node.initializer.canInitialize() do 22:1297: error(scope.filename, node.startPos, "variable initializer `%s` cannot be simplified to a literal", format(node.initializer).ptr); 4300:1298: if !wasAuto do 2254:1299: node.initializer = implicitConvTo(node.initializer, node.type, scope); 4300:1300: if node.getAtNoinit() do 1:1301: error(scope.filename, node.startPos, "`@noinit` variable cant have an initializer"); -:1302: } -:1303: -:1304: // Set a flag allowing const locals|parameters not to use an alloca -:1305: // The is unset during expsema if it turns out that the address is required 15031:1306: if !isStatic && isConst && (scope.func && node.initializer || node.context == parameter || node.context == localForeach) && t.size <= session.ptr_size do -:1307: { 3252:1308: switch t.kind do -:1309: { -:1310: on $bool .. $usize, mul, tkEnumSet, $enum do 2926:1311: node.flags += isImmediate; 326:1312: else do {} -:1313: } -:1314: } -:1315: 15031:1316: if !node.type.isVariableType() && node.context != localForeach do -:1317: { 79:1318: var auto td = t:TypeDeclared*; 79:1319: if t.asTypeFunction() do 2:1320: error(scope.filename, node.startPos, "variable `%s` cannot be of type `%s`, declare an alias or enclose in `()*` to turn the type in a function pointer", -:1321: node.name.text().ptr, format(t).ptr); 77:1322: else do if t:u8* == TypeRange.instance():u8* do 1:1323: error(scope.filename, node.startPos, "variable `%s` cannot be a range", node.name.text().ptr); 152:1324: else do if var auto to = mostModified(t).asTypeOverload() do 2:1325: error(scope.filename, node.startPos, "overload `%s` cannot be used as variable type", format(to).ptr); 74:1326: else do if td && td.declaration.genericParameters && !td.declaration.genericParameters.applied() do 1:1327: error(scope.filename, node.startPos, "cannot use unapplied generic for `%s` type", node.name.text().ptr); 73:1328: else do if !isTypeError(t) do // more useful message already output -:1329: { 16:1330: if t.size == 0 do 15:1331: error(scope.filename, node.startPos, "variable `%s` cannot be of type `%s` because it has no size", node.name.text().ptr, format(t).ptr); -:1332: else do 1:1333: error(scope.filename, node.startPos, "variable `%s` cannot be of type `%s`", node.name.text().ptr, format(t).ptr); -:1334: } -:1335: } 15031:1336: if node.name == thisToken() && isEscape !in node.flags do -:1337: { 1943:1338: var auto tp = node.type.asTypePointer(); 1943:1339: var auto ta = tp ? tp.modified.asTypeAggregate() else null; 1943:1340: if !ta do 2:1341: error(scope.filename, node.startPos, "the `this` parameter type can only be a pointer to a `class`, a `struct` or an `union`"); -:1342: } 15031:1343: if node.getAtTLS() && !isStatic do -:1344: { 1:1345: error(scope.filename, node.startPos, "only `static` variables can be `@tls`"); -:1346: } -:1347: // slices never own memory 30062:1348: if var auto ts = node.type.asTypeSlice() do 437:1349: node.flags += VariableFlag.skipManagment; -:1350: 15031:1351: node.progress = SemanticProgress.done; 15031:1352: } -:1353: -:1354: @override function visitVersionBlockDeclaration(VersionBlockDeclaration* node) -:1355: { 148:1356: if node.thenDeclarations do visitDeclarations(node.thenDeclarations); 19:1357: else do if node.elseDeclarations do visitDeclarations(node.elseDeclarations); 82:1358: } -:1359:} -:1360: -:1361:function setLinkageName(Declaration* node) -:1362:{ 24797:1363: if node.linkageName.length /*|| node.isGeneric()*/ || !node.symbol || node.kind == $import do 2213:1364: return; -:1365: -:1366: // function type 22584:1367: if node.kind == $unit do -:1368: { 472:1369: node.linkageName = node.symbol.fqn(true).tokenChainText(); 472:1370: return; -:1371: } 22112:1372: if !node.name do -:1373: { 122:1374: node.linkageName = format(node); -:1375: //printf("%s\n", node.linkageName.ptr); 122:1376: return; -:1377: } -:1378: // variables, locals and parameters are special cases 43980:1379: if var auto vd = symToVarDecl(node.symbol) do -:1380: { 15036:1381: const auto isGlobal = node.symbol.parent.kind in unitKinds || node.isStatic(); 15036:1382: vd.linkageName = isGlobal && vd.linkageKind == LinkageKind.fqn ? vd.symbol.fqn(true).tokenChainText() else vd.name.text(); -:1383: //printf("%s\n", node.linkageName.ptr); 15036:1384: return; -:1385: } -:1386: // standard C linkage name or styx FQN 6954:1387: if !node.genericParameters || !node.genericParameters.applied() do -:1388: { 6954:1389: node.linkageName = node.linkageKind == foreign ? node.name.text() 6106:1390: else node.symbol.fqn(true).tokenChainText(); -:1391: //printf("%s\n", node.linkageName.ptr); 6954:1392: return; -:1393: } -:1394: assert(0, "applied generic should have its name set during application"); -:1395:} -:1396: -:1397:@public function setGenericParametersLinkageName(GenericParameters* node) -:1398:{ 462:1399: assert(!node.linkageName); 462:1400: node.linkageName ~= "["; 462:1401: foreach const auto p in node.parameters do -:1402: { 669:1403: node.linkageName ~= "%"; 669:1404: if !p.applied() do 29:1405: continue; 640:1406: var auto t = (p.appliedExp ? p.appliedExp.type else p.appliedType).resolved(); 640:1407: var auto s = t.asSymbol(); 640:1408: var auto a = s?.astNode ; 1280:1409: if var auto d = a ? a.asDeclaration() else null do -:1410: { 334:1411: setLinkageName(d); 334:1412: assert(d.linkageName.length, format(d).ptr); 334:1413: node.linkageName ~= d.linkageName[]; -:1414: } 306:1415: else do node.linkageName ~= format(t,internalMode); 640:1416: if p.appliedExp && t.kind != $function do 430:1417: node.linkageName ~= "$" ~ format(p.appliedExp,internalMode); -:1418: } 462:1419: node.linkageName ~= "]"; 462:1420:} <<<<<< EOF # path=src/styx/semantic/deprecations.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/semantic/deprecations.sx -: 1:unit styx.semantic.deprecations; -: 2: -: 3:@private import -: 4: styx.ast.base, -: 5: styx.ast.declarations, -: 6: styx.ast.expressions, -: 7: styx.ast.formatter, -: 8: styx.semantic.declarations, -: 9: styx.scope, -:10: styx.session, -:11: styx.symbol, -:12: styx.token, -:13: ; -:14: -:15:/** -:16: * Checks if a symbol is deprecated and emits a warning accordingly. -:17: * -:18: * This function should always be used after `Symbol.searchWild()` and -:19: * `Symbol.searchStrict()`. -:20: * -:21: * Params: -:22: * identifier = The node that gives the identifier that might resolve to deprecated symbol -:23: * declaration = A Type or a Declaration to check -:24: * scope = indicates the unit in which the identifier is used -:25: */ -:26:function checkDeprecated(AstNode* identifier; AstNode* declaration; Scope* scope) -:27:{ 64497:28: var auto d = declaration.asDeclaration(); 64497:29: var auto dt = session.deprecationType; -:30: var Attribute* a; 64497:31: if !d || !(a = d.getAtDeprecated()) || dt == disabled do 64479:32: return; -:33: 18:34: if d.progress == pending do 1:35: declarationSemantic(d, d.scope); -:36: 18:37: var UnitDeclaration* ud = d.symbol.parentUnit(); 18:38: var auto msgFunc = dt == error ? &session.error else &session.warn; -:39: 18:40: if !a.arguments.length do 16:41: msgFunc(scope.filename, identifier.startPos, "identifier `%s` resolved to a deprecated symbol", format(identifier).ptr); -:42: else do 2:43: msgFunc(scope.filename, identifier.startPos, asStringExp(a.arguments[0]).value.text().ptr); 18:44: msgFunc(ud.filename, declaration.startPos, -:45: " `%s`", format(d).ptr); 18:46:} -:47: <<<<<< EOF # path=src/styx/semantic/evaluate.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/semantic/evaluate.sx -: 1:unit styx.semantic.evaluate; -: 2: -: 3:@private import -: 4: styx.ast.base, -: 5: styx.ast.expressions, -: 6: styx.ast.declarations, -: 7: styx.ast.types, -: 8: styx.ast.visitor, -: 9: styx.symbol, -: 10: styx.session, -: 11: styx.token, -: 12: ; -: 13: -: 14: -: 15:/// Returns: `null` if it was not possible to evalate an expression and an expression otherwise. -: 16:function evaluate(Expression* node): Expression* -: 17:{ 8497: 18: if !node || isTypeError(node.type) do 34: 19: return null; 8463: 20: var Evaluator ev = Evaluator.create(node); 8463: 21: ev.visitExpression(node); 8463: 22: return ev.getResult(); -: 23:} -: 24: -: 25:protection (private) -: 26: -: 27:static var Token*[+] versions; -: 28: -: 29:function prepareVersions() -: 30:{ -: 31: static var bool done; 190: 32: if done do return; 60: 33: done = true; -: 34: 60: 35: versions ~= identifier("all"); 106: 36: if asserts in session.additionalChecks do versions ~= identifier("check_asserts"); 106: 37: if bounds in session.additionalChecks do versions ~= identifier("check_bounds"); 106: 38: if switches in session.additionalChecks do versions ~= identifier("check_switches"); 106: 39: if thiscalls in session.additionalChecks do versions ~= identifier("check_thiscalls"); 62: 40: if session.compileUnittest do versions ~= identifier("unittest"); 60: 41: versions ~= session.ptr_size == 32 ? identifier("X86") else identifier("X86_64"); 60: 42: version posix do versions ~= identifier("posix"); -: 43: 67: 44: foreach var auto v in session.versions do versions ~= identifier(v); 60: 45:} -: 46: -: 47:@destructor static function destroyVersions() -: 48:{ 374: 49: foreach var auto v in versions do 373: 50: delete v; 374: 51: versions.decref; 374: 52:} -: 53: -: 54:struct Value -: 55:{ -: 56: var Type* type; -: 57: union As -: 58: { -: 59: var bool $bool; -: 60: var u32 $u32; -: 61: var u64 $u64; -: 62: var s32 $s32; -: 63: var s64 $s64; -: 64: var f64 $f64; -: 65: var s8[] $string; -: 66: } -: 67: var As as; -: 68: var bool defined; -: 69:} -: 70: -: 71:@final class Evaluator : AstVisitor -: 72:{ -: 73: var Value value; -: 74: var Type* originalType; -: 75: var Expression* exp; -: 76: -: 77: @constructor function create(Expression* node) -: 78: { 8463: 79: this.value.type = node.type; 8463: 80: this.originalType = node.type; 8463: 81: this.value.defined = true; 8463: 82: this.exp = node; 8463: 83: } -: 84: -: 85: function invalidateValue() -: 86: { 5160: 87: value.defined = false; 5160: 88: } -: 89: -: 90: function failed(): bool -: 91: { 15277: 92: return !value.defined; -: 93: } -: 94: -: 95: function getResult(): Expression* -: 96: { 8463: 97: if failed() do 5115: 98: return null; 3348: 99: if isTypeBool(value.type.resolved()) do 982:100: return (new BoolExpression).create(exp.startPos, null, value.as.$bool, TypeBool.instance()); 2366:101: else do if value.type.isIntegral() do 2281:102: return (new IntegerExpression).create(exp.startPos, null, value.as.$u64, originalType); 85:103: else do if value.type.isFloating() do 19:104: return (new FloatExpression).create(exp.startPos, null, value.as.$f64, originalType); 66:105: return null; -:106: } -:107: -:108: @override function visitArrayExpression(ArrayExpression* node) -:109: { 5:110: invalidateValue(); 5:111: } -:112: -:113: @override function visitAddExpression(AddExpression* node) -:114: { 41:115: if failed() do return; -:116: 41:117: visitConcreteExpression(node.left); 41:118: const Value v1 = value; 60:119: if failed() do return; 22:120: visitConcreteExpression(node.right); 22:121: const Value v2 = value; 22:122: if failed() do return; -:123: 22:124: var auto t = node.type; 22:125: if t.isIntegral() do -:126: { 19:127: value.defined = true; 19:128: value.as.$s64 = v1.as.$s64 + v2.as.$s64; -:129: } 3:130: else do if t.isFloating() do -:131: { 2:132: value.defined = true; 2:133: value.as.$f64 = v1.as.$f64 + v2.as.$f64; -:134: } 1:135: else do invalidateValue(); // Ptr arithmetic 22:136: } -:137: -:138: @override function visitAndExpression(AndExpression* node) -:139: { 4:140: if failed() do return; -:141: 4:142: visitConcreteExpression(node.left); 4:143: const Value v1 = value; 7:144: if failed() do return; 1:145: visitConcreteExpression(node.right); 1:146: const Value v2 = value; 1:147: if failed() do return; -:148: 1:149: assert(node.type.isIntegral()); 1:150: value.defined = true; 1:151: value.as.$s64 = v1.as.$s64 & v2.as.$s64; 1:152: } -:153: -:154: @override function visitAndAndExpression(AndAndExpression* node) -:155: { 564:156: if failed() do return; -:157: 564:158: visitConcreteExpression(node.left); 564:159: const Value v1 = value; 1110:160: if failed() do return; 18:161: visitConcreteExpression(node.right); 18:162: const Value v2 = value; 21:163: if failed() do return; -:164: 15:165: value.as.$bool = v1.as.$bool && v2.as.$bool; 15:166: value.defined = true; 15:167: } -:168: -:169: @override function visitBoolExpression(BoolExpression* node) -:170: { 732:171: value.defined = true; 732:172: value.as.$bool = node.value:bool; 732:173: value.type = TypeBool.instance(); 732:174: } -:175: -:176: @override function visitCallExpression(CallExpression* node) -:177: { 649:178: invalidateValue(); 649:179: } -:180: -:181: @override function visitCastExpression(CastExpression* node) -:182: { 816:183: visitConcreteExpression(node.expression); 935:184: if failed() do return; -:185: 697:186: var auto t = node.type.resolved(); 697:187: switch node.kind do -:188: { 16:189: on intExt do { value.type = t; } 1:190: on fpExt do { value.type = t; } 8:191: on intToFp do { value.type = t; value.as.$f64 = value.as.$u64; } 668:192: on intTrunc do { value.type = t; } 3:193: on fpTrunc do { value.type = t; } 2:194: on fpToInt do { value.type = t; value.as.$u64 = value.as.$f64:u64; } 2:195: on bitCast do { value.type = t; } -:196: on toCond do { assert(0, "toCond should not happen during evaluate()"); } 2:197: on nullCast do { value.type = t; } -:198: } 697:199: } -:200: -:201: @override function visitCmpExpression(CmpExpression* node) -:202: { 3957:203: visitConcreteExpression(node.left); 7713:204: if failed() do return; 201:205: var Value v1 = value; 201:206: visitConcreteExpression(node.right); 248:207: if failed() do return; 154:208: var Value v2 = value; -:209: 154:210: var TypePointer* tp1 = asTypePointer(v1.type); 154:211: var TypePointer* tp2 = asTypePointer(v2.type); 154:212: const bool isStr = node.left.operator == node.right.operator && node.right.operator == stringLiteral; 154:213: if isStr && tp1 && tp2 && isTypeS8(tp1.modified.resolved()) && 9:214: isTypeS8(tp2.modified.resolved()) do -:215: { 9:216: if node.operator == TokenType.equal do -:217: { 6:218: value.as.$bool = v1.as.string == v2.as.string; 6:219: value.defined = true; 6:220: value.type = TypeBool.instance(); -:221: } 3:222: else do if node.operator == TokenType.notEqual do -:223: { 2:224: value.as.$bool = v1.as.string != v2.as.string; 2:225: value.defined = true; 2:226: value.type = TypeBool.instance(); -:227: } 1:228: else do invalidateValue(); -:229: } 145:230: else do if v1.type.isFloating() && v2.type.isFloating() do -:231: { 16:232: switch node.operator do -:233: { -:234: on TokenType.equal do -:235: { 9:236: value.as.$bool = v1.as.$f64 == v2.as.$f64; 9:237: value.defined = true; 9:238: value.type = TypeBool.instance(); -:239: } -:240: on TokenType.notEqual do -:241: { 3:242: value.as.$bool = v1.as.$f64 != v2.as.$f64; 3:243: value.defined = true; 3:244: value.type = TypeBool.instance(); -:245: } -:246: on TokenType.greater do -:247: { 1:248: value.as.$bool = v1.as.$f64 > v2.as.$f64; 1:249: value.defined = true; 1:250: value.type = TypeBool.instance(); -:251: } -:252: on TokenType.greaterEqual do -:253: { 1:254: value.as.$bool = v1.as.$f64 >= v2.as.$f64; 1:255: value.defined = true; 1:256: value.type = TypeBool.instance(); -:257: } -:258: on TokenType.lesser do -:259: { 1:260: value.as.$bool = v1.as.$f64 < v2.as.$f64; 1:261: value.defined = true; 1:262: value.type = TypeBool.instance(); -:263: } -:264: on TokenType.lesserEqual do -:265: { 1:266: value.as.$bool = v1.as.$f64 <= v2.as.$f64; 1:267: value.defined = true; 1:268: value.type = TypeBool.instance(); -:269: } -:270: } -:271: } 129:272: else do if v1.type.isSigned() || v2.type.isSigned() do -:273: { 22:274: switch node.operator do -:275: { -:276: on TokenType.equal do -:277: { 7:278: value.as.$bool = v1.as.$s64 == v2.as.$s64; 7:279: value.defined = true; 7:280: value.type = TypeBool.instance(); -:281: } -:282: on TokenType.notEqual do -:283: { 4:284: value.as.$bool = v1.as.$s64 != v2.as.$s64; 4:285: value.defined = true; 4:286: value.type = TypeBool.instance(); -:287: } -:288: on TokenType.greater do -:289: { 2:290: value.as.$bool = v1.as.$s64 > v2.as.$s64; 2:291: value.defined = true; 2:292: value.type = TypeBool.instance(); -:293: } -:294: on TokenType.greaterEqual do -:295: { 2:296: value.as.$bool = v1.as.$s64 >= v2.as.$s64; 2:297: value.defined = true; 2:298: value.type = TypeBool.instance(); -:299: } -:300: on TokenType.lesser do -:301: { 5:302: value.as.$bool = v1.as.$s64 < v2.as.$s64; 5:303: value.defined = true; 5:304: value.type = TypeBool.instance(); -:305: } -:306: on TokenType.lesserEqual do -:307: { 2:308: value.as.$bool = v1.as.$s64 <= v2.as.$s64; 2:309: value.defined = true; 2:310: value.type = TypeBool.instance(); -:311: } -:312: } -:313: } -:314: else do -:315: { 107:316: switch node.operator do -:317: { -:318: on TokenType.equal do -:319: { 80:320: value.as.$bool = v1.as.$u64 == v2.as.$u64; 80:321: value.defined = true; 80:322: value.type = TypeBool.instance(); -:323: } -:324: on TokenType.notEqual do -:325: { 22:326: value.as.$bool = v1.as.$u64 != v2.as.$u64; 22:327: value.defined = true; 22:328: value.type = TypeBool.instance(); -:329: } -:330: on TokenType.greater do -:331: { 2:332: value.as.$bool = v1.as.$u64 > v2.as.$u64; 2:333: value.defined = true; 2:334: value.type = TypeBool.instance(); -:335: } -:336: on TokenType.greaterEqual do -:337: { 1:338: value.as.$bool = v1.as.$u64 >= v2.as.$u64; 1:339: value.defined = true; 1:340: value.type = TypeBool.instance(); -:341: } -:342: on TokenType.lesser do -:343: { 1:344: value.as.$bool = v1.as.$u64 < v2.as.$u64; 1:345: value.defined = true; 1:346: value.type = TypeBool.instance(); -:347: } -:348: on TokenType.lesserEqual do -:349: { 1:350: value.as.$bool = v1.as.$u64 <= v2.as.$u64; 1:351: value.defined = true; 1:352: value.type = TypeBool.instance(); -:353: } -:354: } -:355: } 154:356: } -:357: -:358: @override function visitConditionalExpression(ConditionalExpression* node) -:359: { 6:360: visitConcreteExpression(node.condition); 10:361: if failed() do return; 2:362: if value.as.$u64 != 0 do 1:363: visitConcreteExpression(node.thenExpression); -:364: else do 1:365: visitConcreteExpression(node.elseExpression); 2:366: } -:367: -:368: @override function visitDivExpression(DivExpression* node) -:369: { 2:370: if failed() do return; -:371: 2:372: visitConcreteExpression(node.left); 2:373: if failed() do return; 2:374: const Value v1 = value; 2:375: visitConcreteExpression(node.right); 2:376: if failed() do return; 2:377: const Value v2 = value; -:378: 2:379: var auto t = node.type; 2:380: if t.isIntegral() do -:381: { 1:382: value.defined = true; 1:383: value.as.$s64 = v1.as.$s64 / v2.as.$s64; -:384: } 1:385: else do if t.isFloating() do -:386: { 1:387: value.defined = true; 1:388: value.as.$f64 = v1.as.$f64 / v2.as.$f64; -:389: } -:390: else do assert(0); 2:391: } -:392: -:393: @override function visitDotExpression(DotExpression* node) -:394: { 1144:395: if var EnumMember* em = symToEnumMember(node.dotted.symbol) do 32:396: visitConcreteExpression(em.value); 540:397: else do invalidateValue(); 572:398: } -:399: -:400: @override function visitFloatExpression(FloatExpression* node) -:401: { 54:402: value.type = TypeF64.instance(); 54:403: value.defined = true; 54:404: value.as.$f64 = node.value; 54:405: } -:406: -:407: @override function visitIdentExpression(IdentExpression* node) -:408: { 7160:409: if var EnumMember* em = symToEnumMember(node.symbol) do 226:410: visitConcreteExpression(em.value); 3354:411: else do invalidateValue(); 3580:412: } -:413: -:414: @override function visitIndexExpression(IndexExpression* node) -:415: { 71:416: invalidateValue(); 71:417: } -:418: -:419: @override function visitInExpression(InExpression* node) -:420: { 63:421: invalidateValue(); 63:422: } -:423: -:424: @override function visitIntegerExpression(IntegerExpression* node) -:425: { 2629:426: var auto t = node.type.resolved(); 2629:427: if t.isSigned() do 33:428: value.type = t.size == 4 ? TypeS32.instance() else TypeS64.instance(); -:429: else do 2596:430: value.type = t.size == 4 ? TypeU32.instance() else TypeU64.instance(); 2629:431: value.defined = true; 2629:432: value.as.$u64 = node.value; 2629:433: } -:434: -:435: @override function visitLengthExpression(LengthExpression* node) -:436: { 225:437: invalidateValue(); 225:438: } -:439: -:440: @override function visitLShiftExpression(LShiftExpression* node) -:441: { 1:442: if failed() do return; -:443: 1:444: visitConcreteExpression(node.left); 1:445: if failed() do return; 1:446: const Value v1 = value; 1:447: visitConcreteExpression(node.right); 1:448: if failed() do return; 1:449: const Value v2 = value; -:450: 1:451: if node.type.isIntegral() do -:452: { 1:453: value.defined = true; 1:454: value.as.$s64 = v1.as.$s64 << v2.as.$s64; -:455: } -:456: else do assert(0); 1:457: } -:458: -:459: @override function visitModExpression(ModExpression* node) -:460: { 2:461: if failed() do return; -:462: 2:463: visitConcreteExpression(node.left); 2:464: if failed() do return; 2:465: const Value v1 = value; 2:466: visitConcreteExpression(node.right); 2:467: if failed() do return; 2:468: const Value v2 = value; -:469: 2:470: var auto t = node.type; 2:471: if t.isIntegral() do -:472: { 1:473: value.defined = true; 1:474: value.as.$s64 = v1.as.$s64 % v2.as.$s64; -:475: } 1:476: else do if t.isFloating() do -:477: { 1:478: value.defined = true; 1:479: value.as.$f64 = v1.as.$f64 % v2.as.$f64; -:480: } -:481: else do assert(0); 2:482: } -:483: -:484: @override function visitMulExpression(MulExpression* node) -:485: { 14:486: if failed() do return; -:487: 14:488: visitConcreteExpression(node.left); 15:489: if failed() do return; 13:490: const Value v1 = value; 13:491: visitConcreteExpression(node.right); 13:492: if failed() do return; 13:493: const Value v2 = value; -:494: 13:495: var auto t = node.type; 13:496: if t.isIntegral() do -:497: { 12:498: value.defined = true; 12:499: value.as.$s64 = v1.as.$s64 * v2.as.$s64; -:500: } 1:501: else do if t.isFloating() do -:502: { 1:503: value.defined = true; 1:504: value.as.$f64 = v1.as.$f64 * v2.as.$f64; -:505: } -:506: else do assert(0); 13:507: } -:508: -:509: @override function visitNegExpression(NegExpression* node) -:510: { 249:511: visitConcreteExpression(node.expression); 249:512: if value.defined do -:513: { 249:514: if value.type.isFloating() do 5:515: value.as.$f64 = -value.as.$f64; -:516: else do 244:517: value.as.$s64 = -value.as.$s64; -:518: } 249:519: } -:520: -:521: @override function visitNotExpression(NotExpression* node) -:522: { 388:523: visitConcreteExpression(node.expression); 429:524: if value.defined do value.as.$u64 = !value.as.$u64; 388:525: } -:526: -:527: @override function visitOneCompExpression(OneCompExpression* node) -:528: { 4:529: visitConcreteExpression(node.expression); 4:530: if value.defined do -:531: { 3:532: if value.type.isSigned() do 1:533: value.as.$s64 = ~value.as.$s64; -:534: else do 2:535: value.as.$u64 = ~value.as.$u64; 3:536: return; -:537: } 1:538: } -:539: -:540: @override function visitPtrExpression(PtrExpression* node) -:541: { 3:542: invalidateValue(); 3:543: } -:544: -:545: @override function visitRShiftExpression(RShiftExpression* node) -:546: { 1:547: if failed() do return; -:548: 1:549: visitConcreteExpression(node.left); 1:550: if failed() do return; 1:551: const Value v1 = value; 1:552: visitConcreteExpression(node.right); 1:553: if failed() do return; 1:554: const Value v2 = value; -:555: 1:556: assert(node.type.isIntegral()); 1:557: value.defined = true; 1:558: value.as.$s64 = v1.as.$s64 >> v2.as.$s64; 1:559: } -:560: -:561: @override function visitRangeExpression(RangeExpression* node) -:562: { 28:563: invalidateValue(); 28:564: } -:565: -:566: @override function visitRefCountExpression(RefCountExpression* node) -:567: { 3:568: invalidateValue(); 3:569: } -:570: -:571: @override function visitStringExpression(StringExpression* node) -:572: { 84:573: value.as.string = node.value.text(); 84:574: value.type = node.type; 84:575: value.defined = true; 84:576: } -:577: -:578: @override function visitSubExpression(SubExpression* node) -:579: { 6:580: if failed() do return; -:581: 6:582: visitConcreteExpression(node.left); 7:583: if failed() do return; 5:584: const Value v1 = value; 5:585: visitConcreteExpression(node.right); 5:586: if failed() do return; 5:587: const Value v2 = value; -:588: 5:589: var auto t = node.type; 5:590: if t.isIntegral() do -:591: { 3:592: value.defined = true; 3:593: value.as.$s64 = v1.as.$s64 - v2.as.$s64; -:594: } 2:595: else do if t.isFloating() do -:596: { 1:597: value.defined = true; 1:598: value.as.$f64 = v1.as.$f64 - v2.as.$f64; -:599: } 1:600: else do invalidateValue(); // Ptr arithmetic 5:601: } -:602: -:603: @override function visitTypeExpression(TypeExpression* node) -:604: { 216:605: invalidateValue(); 216:606: } -:607: -:608: @override function visitOrExpression(OrExpression* node) -:609: { 3:610: if failed() do return; -:611: 3:612: visitConcreteExpression(node.left); 5:613: if failed() do return; 1:614: const Value v1 = value; 1:615: visitConcreteExpression(node.right); 1:616: if failed() do return; 1:617: const Value v2 = value; -:618: 1:619: assert(node.type.isIntegral()); 1:620: value.defined = true; 1:621: value.as.$s64 = v1.as.$s64 | v2.as.$s64; 1:622: } -:623: -:624: @override function visitOrOrExpression(OrOrExpression* node) -:625: { 242:626: if failed() do return; -:627: 242:628: visitConcreteExpression(node.left); 481:629: if failed() do return; 3:630: const Value v1 = value; 3:631: visitConcreteExpression(node.right); 5:632: if failed() do return; 1:633: const Value v2 = value; -:634: 1:635: value.as.$bool = v1.as.$bool || v2.as.$bool; 1:636: value.defined = true; 1:637: } -:638: -:639: @override function visitVersionIdentExpression(VersionIdentExpression* node) -:640: { 125:641: prepareVersions(); 125:642: value.as.$bool = false; 125:643: var auto i = node.identifier.iptr(); 125:644: foreach var auto v in versions do 746:645: if i == v.iptr() do 102:646: break value.as.$bool = true; 125:647: } -:648: -:649: @override function visitXorExpression(XorExpression* node) -:650: { 2:651: if failed() do return; -:652: 2:653: visitConcreteExpression(node.left); 3:654: if failed() do return; 1:655: const Value v1 = value; 1:656: visitConcreteExpression(node.right); 1:657: if failed() do return; 1:658: const Value v2 = value; -:659: 1:660: assert(node.type.isIntegral()); 1:661: value.defined = true; 1:662: value.as.$s64 = v1.as.$s64 ^ v2.as.$s64; 1:663: } -:664:} -:665: <<<<<< EOF # path=src/styx/semantic/expressions.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/semantic/expressions.sx -: 1:unit styx.semantic.expressions; -: 2: -: 3:@private import -: 4: styx.ast.base, -: 5: styx.ast.declarations, -: 6: styx.ast.expressions, -: 7: styx.ast.formatter, -: 8: styx.ast.types, -: 9: styx.ast.visitor, -: 10: styx.position, -: 11: styx.semantic.declarations, -: 12: styx.semantic.deprecations, -: 13: styx.semantic.evaluate, -: 14: styx.semantic.memulator, -: 15: styx.semantic.types, -: 16: styx.session, -: 17: styx.scope, -: 18: styx.symbol, -: 19: styx.token, -: 20: ; -: 21: -: 22:/// Runs the semantics of an expression -: 23:function expressionSemantic(Expression* node; Scope* scope): Expression* -: 24:{ 169213: 25: if node.type do 52107: 26: return node; 117106: 27: var auto es = ExpressionSemantic.create(node, scope); 117106: 28: es.visitConcreteExpression(node); 117106: 29: node = es.result; 117106: 30: return node; -: 31:} -: 32: -: 33:/** Returns: an OperatorOverloadMacro or the input expression depending -: 34: * on the result of `getMacroOperatorKind()` over the input expression. */ -: 35:function expToMacroOperator(Expression* e): Expression* -: 36:{ 156: 37: switch getMacroOperatorKind(e) do -: 38: { 152: 39: on default do return e; 2: 40: on indexAssign do return (new OpOverloadMacro).create(e, OpOverloadKind.indexAssign); 2: 41: on sliceAssign do return (new OpOverloadMacro).create(e, OpOverloadKind.sliceAssign); -: 42: } -: 43:} -: 44: -: 45:/** -: 46: * Try to implicitly convert an expression to the type of another. -: 47: * -: 48: * Params: -: 49: * sourceExpr = the source to convert -: 50: * targetType = the target the type -: 51: * scope = the scope to analyze newly created expressions -: 52: * -: 53: * Returns: Either a new or a modified expression. -: 54: */ -: 55:function implicitConvTo(Expression* sourceExpr; Type* targetType; Scope* scope): Expression* -: 56:{ -: 57: //assert(targetType); -: 58: //assert(sourceExpr.type); -: 59: 87096: 60: var auto t1 = sourceExpr.type.resolved(); 87096: 61: var auto t2 = targetType.resolved(); -: 62: -: 63: function impConvError(): auto -: 64: { 840: 65: session.error(scope.filename, sourceExpr.startPos, -: 66: "cannot implicitly convert `%s` of type `%s` to type `%s`", -: 67: format(sourceExpr).ptr, format(t1).ptr, format(t2).ptr); 840: 68: return null; -: 69: } -: 70: 87096: 71: const auto ck = getCastKind(sourceExpr, targetType); 87096: 72: switch ck do -: 73: { -: 74: on CastKind.same do -: 75: { 75363: 76: var auto tp1 = asTypePointer(t1); 75363: 77: var auto tp2 = asTypePointer(t2); 75363: 78: var auto tf1 = tp1 ? asTypeFunction(tp1.modified) else null; 75363: 79: var auto tf2 = tp2 ? asTypeFunction(tp2.modified) else null; -: 80: /* better diagnostic for this case: -: 81: ``` -: 82: alias FunPtr = (function (A* this))*; -: 83: var FunPtr fp = &agg.somethingVirtual; // fp(thisParam); would not be a virtual call -: 84: var FunPtr fp2 = (&agg.somethingVirtual):FunPtr; // allow this however -: 85: ``` -: 86: */ 75363: 87: if tf1 && tf2 && tf1.declaration.virtualIndex != -1 && tf2.declaration.virtualIndex == -1 do -: 88: { 1: 89: session.error(scope.filename, sourceExpr.startPos, "conversion to non-virtual from an `@virtual` function"); 1: 90: return null; -: 91: } 75362: 92: return sourceExpr; -: 93: } -: 94: // implicit OK -: 95: on CastKind.staticCastP, CastKind.funRet do 2329: 96: return (new CastExpression).create(sourceExpr.startPos, sourceExpr, t2, CastKind.bitCast, true); -: 97: on CastKind.intExt, CastKind.fpExt, CastKind.intToFp, CastKind.nullCast, CastKind.staToPtr, CastKind.strToSta do 5213: 98: return (new CastExpression).create(sourceExpr.startPos, sourceExpr, t2, ck, true); -: 99: on CastKind.intToSet do -: 100: { 127: 101: var auto te = asTypeEnumSet(t2).declaration.asTypeDeclared.asTypeEnum(); 127: 102: return implicitConvTo(sourceExpr, te.declaration.type, scope); -: 103: } -: 104: on CastKind.intToEnum do -: 105: { 4: 106: var auto tes = t2.asTypeEnumSet(); 4: 107: var auto te2 = tes ? tes.declaration.asTypeDeclared.asTypeEnum() else t2.asTypeEnum(); 4: 108: return implicitConvTo(sourceExpr, te2.declaration.getEnumRootType(), scope); -: 109: } -: 110: on CastKind.staElems do -: 111: { 38: 112: var auto ae = asArrayExp(sourceExpr); 38: 113: var auto de = asDeclExp(sourceExpr); 38: 114: if !ae && de do -: 115: { 2: 116: if var auto da = de.expression do 2: 117: if var auto as = asAssignExp(da) do 1: 118: ae = asArrayExp(as.right); -: 119: } 38: 120: return castArrayLiteralElements(ae, asTypeStaticArray(targetType), scope); -: 121: } -: 122: on CastKind.staToESet do 33: 123: return castStaticArrayToEnumSet(sourceExpr, asTypeEnumSet(t2), scope); -: 124: on CastKind.strToChar do 869: 125: return (new IntegerExpression).create(sourceExpr.startPos, null, asStringExp(sourceExpr).value.text()[0], t2); -: 126: on CastKind.strToDyna, CastKind.staToDyna, CastKind.rcaToDyna do -: 127: { 990: 128: if var auto e = emptyArrayToSlice(sourceExpr, t2, scope) do 9: 129: return e; 486: 130: var auto sl = (new SliceExpression).create(sourceExpr.startPos, sourceExpr); 486: 131: return expressionSemantic(sl, scope); -: 132: } -: 133: on CastKind.strToRca, CastKind.staToRca, CastKind.dynaToRca do -: 134: { 468: 135: if var auto e = emptyArrayToSlice(sourceExpr, t2, scope) do 3: 136: sourceExpr = e; 234: 137: var auto rae = (new RcaAssignExpression).create(sourceExpr.startPos, sourceExpr); 234: 138: return expressionSemantic(rae, scope); -: 139: } -: 140: on CastKind.opTrue do -: 141: { 2: 142: session.startGagging(); 2: 143: var auto tc = toCondition(sourceExpr, scope); 2: 144: session.stopGagging(); 2: 145: return tc ? impConvError(); -: 146: } -: 147: on CastKind.toCond, CastKind.intTrunc do -: 148: { -: 149: var bool allow; 4162: 150: if var auto ie = asIntegerExp(sourceExpr) do -: 151: { 1533: 152: if !t2.isSigned() do -: 153: { 1443: 154: var u64 v = ie.value; 1443: 155: const auto inBoolRange= v <= 1; 1443: 156: const auto inU8Range = v <= u8.max; 1443: 157: const auto inU16Range = v <= u16.max; 1443: 158: const auto inU32Range = v <= u32.max; 1443: 159: allow = (inBoolRange && t2.kind == $bool) || 1438: 160: (inU8Range && t2.size >= 8) || 13: 161: (inU16Range && t2.size >= 16) || 7: 162: (inU32Range && t2.size >= 32) ; -: 163: } -: 164: else do -: 165: { 90: 166: var s64 v = ie.value:s64; 90: 167: const auto inBoolRange= v <= 1; 90: 168: const auto inS8Range = v <= s8.max && v >= s8.min; 90: 169: const auto inS16Range = v <= s16.max && v >= s16.min; 90: 170: const auto inS32Range = v <= s32.max && v >= s32.min; 90: 171: allow = (inBoolRange && t2.kind == $bool) || 90: 172: (inS8Range && t2.size >= 8) || 6: 173: (inS16Range && t2.size >= 16) || 2: 174: (inS32Range && t2.size >= 32) ; -: 175: } -: 176: } 2081: 177: return allow ? (new CastExpression).create(sourceExpr.startPos, sourceExpr, t2, CastKind.intTrunc, true) else impConvError(); -: 178: } -: 179: on CastKind.staticCastS do 3: 180: return forceCast(sourceExpr, t2); -: 181: on CastKind.tupToElem do 2: 182: return tupleToElement(sourceExpr, t2, scope); -: 183: on CastKind.elemToTup do 1: 184: return elementToTuple(sourceExpr, t2, scope); -: 185: on CastKind.tupToStruct do 42: 186: if var auto e = tupleToStruct(sourceExpr, t2, scope) 20: 187: do return e; 1: 188: else do return impConvError(); -: 189: 281: 190: else do return impConvError(); -: 191: } -: 192:} -: 193: -: 194:/** -: 195: * Try to rewrite the input expression as a condition. -: 196: * -: 197: * Returns: -: 198: * null if not possible, the input expression if it -: 199: * was already a comparison, a `CmpExpression*` on success. -: 200: */ -: 201:function toCondition(Expression* node; Scope* scope): Expression* -: 202:{ -: 203: var Expression* result; 10616: 204: switch node.operator do -: 205: { -: 206: on equal, notEqual, greater, greaterEqual, lesser, lesserEqual, andAnd, orOr do 5341: 207: return node; -: 208: on ass do -: 209: { 40: 210: if !node.parens do -: 211: { 2: 212: session.error(scope.filename, node.startPos, "assignments cannot be used as condition"); 2: 213: node.type = TypeError.instance(); 2: 214: return node; -: 215: } 38: 216: continue on else; -: 217: } -: 218: on amp, pipe do -: 219: { 4: 220: if !node.parens do -: 221: { 2: 222: session.error(scope.filename, node.startPos, "binary `%s` used as condition requires an explicit comparison", -: 223: tokenString[node.operator].ptr); 2: 224: node.type = TypeError.instance(); 2: 225: return node; -: 226: } 2: 227: continue on else; -: 228: } -: 229: else do -: 230: { 5271: 231: assert (node.type, "toCondition called too early, exp should have a type"); 5271: 232: var auto t = node.type.resolved(); -: 233: 10542: 234: if var auto e = tryOperatorOverload(BoolExpression.getFalse(), [node][]) do 8: 235: return expressionSemantic(e, scope.pushNested()); -: 236: 5263: 237: switch t.kind do -: 238: { -: 239: on $bool do 2302: 240: result = node; -: 241: // integer type, returns (exp != 0) -: 242: on $u8, $u16, $u32, $u64, $s8, $s16, $s32, $s64, $enum, tkEnumSet do 755: 243: result = (new CmpExpression).create( -: 244: node.startPos, notEqual, node, (new IntegerExpression).create(node.startPos, null, 0, t), TypeBool.instance() -: 245: ); -: 246: // fp type, returns (exp != 0.0) -: 247: on $f32, $f64 do 13: 248: result = (new CmpExpression).create( -: 249: node.startPos, notEqual, node, (new FloatExpression).create(node.startPos, null, 0.0, t), TypeBool.instance() -: 250: ); -: 251: // nullable type, returns (exp != null:()) -: 252: on mul do 2124: 253: result = (new CmpExpression).create( -: 254: node.startPos, notEqual, node, (new NullExpression).create(node.startPos, t), TypeBool.instance() -: 255: ); -: 256: // arrays, returns (exp.length != 0) -: 257: on tkSlice, tkRca do 30: 258: result = toCondition((new LengthExpression).create(node, false, TypeUSize()), scope); 39: 259: else do {} -: 260: } -: 261: } -: 262: } 5302: 263: if !result do session.error(scope.filename, node.startPos, -: 264: "expression `%s` of type `%s` cannot be used as a condition", -: 265: format(node).ptr, format(node.type.resolved()).ptr); 5263: 266: return result; -: 267:} -: 268: -: 269:protection (private) -: 270: -: 271:/// Result provided when trying to match an argument with a parameter. -: 272:struct ArgToParamResult -: 273:{ -: 274: /// The new argument -: 275: var Expression* conv; -: 276: /// The return code. -: 277: var ArgToParamKind kind; -: 278:} -: 279: -: 280:enum ArgToParamKind : u8 -: 281:{ -: 282: no_wrongType, /// The argument type cant be converted implicitly to the param type -: 283: no_constToVar, /// The argument is const but the parameter expects a modifiable lvalue -: 284: no_exact, /// The parameter is var or init but that argument type doedsn't match exactly -: 285: no_lvalue, /// The parameter is var or init but the argument is not a lvalue. -: 286: no_static, /// The parameter only accepts static variables -: 287: yes_implicitConversion, /// The argument can be passed, but after conversion. -: 288: yes_exact, /// The argument can be passed as-is. -: 289: maybe_tup, /// does not match but tuple expansion can be tried -: 290:} -: 291: -: 292:@final class ExpressionSemantic : AstVisitor -: 293:{ -: 294: var Expression* result; -: 295: var Scope* scope; -: 296: -: 297: /// Assuming `node` requires `this`, make `this` explicit so that it can be automatically escaped. -: 298: function addThisExpForEscape(IdentExpression* node; Scope* scope): bool -: 299: { 5178: 300: var auto fd = scope.func; 5178: 301: if !fd || FunctionFlag.isNested !in fd.flags || ScopeFlag.isDotDotted in scope.flags do 5151: 302: return false; 27: 303: var auto a = scope.parentFunc(); 27: 304: var auto fd0 = asFunctionDeclaration(a); 27: 305: if fd0.parameters.length && fd0.parameters[0].name == thisToken() do -: 306: { 26: 307: node.symbol = null; 26: 308: result = (new DotExpression).create(node.startPos, (new ThisExpression).create(node.startPos), node); 26: 309: result = expressionSemantic(result, scope); 26: 310: return true; -: 311: } 1: 312: return false; -: 313: } -: 314: -: 315: function argToParam(VariableDeclaration* param; Expression* arg; Scope* sc): ArgToParamResult -: 316: { -: 317: var ArgToParamResult atp; 18552: 318: var auto pType = param.type.resolved(); 18552: 319: var auto aType = arg.type.resolved(); 18552: 320: var auto tt = asTypeTuple(aType); 18552: 321: var auto vd = symToVarDecl(arg.symbol); 18552: 322: const auto exact = ScopeFlag.firstOverloadPass in sc.flags; -: 323: 18552: 324: const auto paramIsVar = param.isVar(); 18552: 325: const auto paramIsConst = param.isConst(); 18552: 326: const auto paramIsStatic= param.isStatic(); 18552: 327: const auto argIsConst = vd && vd.isConst(); 18552: 328: const auto argIsStatic = vd && vd.isStatic(); -: 329: 18552: 330: if paramIsVar do -: 331: { 800: 332: if vd do 793: 333: vd.flags -= isImmediate; 800: 334: if !vd && !arg.isLvalue() do 1: 335: atp.kind = ArgToParamKind.no_lvalue; 799: 336: else do if paramIsStatic && !argIsStatic do 1: 337: atp.kind = ArgToParamKind.no_static; 798: 338: else do if argIsConst && !paramIsConst do 2: 339: atp.kind = ArgToParamKind.no_constToVar; 796: 340: else do if aType != pType do 2: 341: atp.kind = tt ? ArgToParamKind.maybe_tup else ArgToParamKind.no_exact; -: 342: else do -: 343: { 794: 344: atp.kind = ArgToParamKind.yes_exact; 794: 345: atp.conv = arg; -: 346: } -: 347: } 17752: 348: else do if exact do -: 349: { 995: 350: atp.conv = arg; 995: 351: if aType != pType do -: 352: { -: 353: // trying overloads, first pass, -: 354: // need a dummy error due to gagged error count checked 581: 355: error(scope.filename, arg.startPos, ""); 581: 356: atp.kind = ArgToParamKind.no_wrongType; -: 357: } 414: 358: else do atp.kind = ArgToParamKind.yes_exact; -: 359: } 16757: 360: else do if tt do -: 361: { 13: 362: session.startGagging(); 13: 363: var auto e = implicitConvTo(arg, pType, sc); 13: 364: session.stopGagging(); 13: 365: if e do -: 366: { 9: 367: atp.kind = e:u8* == arg:u8* ? ArgToParamKind.yes_exact else ArgToParamKind.yes_implicitConversion; 9: 368: atp.conv = e; -: 369: } 4: 370: else do atp.kind = ArgToParamKind.maybe_tup; -: 371: } 33488: 372: else do if var auto newArg = implicitConvTo(arg, pType, sc) do -: 373: { 16691: 374: atp.conv = newArg; 16691: 375: atp.kind = newArg:u8* == arg:u8* ? ArgToParamKind.yes_exact else ArgToParamKind.yes_implicitConversion; -: 376: } 18552: 377: return atp; -: 378: } -: 379: -: 380: function checkIfAssignable(Expression* node) -: 381: { 7202: 382: if node.isAssignable() || isTypeError(node.type) do 7161: 383: return; 82: 384: if var auto ce = asCallExp(node) do 2: 385: if ce.type.resolved().kind != $var do 2: 386: return error(scope.filename, node.startPos, "cannot modify return of `%s`", format(node).ptr); 39: 387: if node.isLiteral() do 10: 388: return error(scope.filename, node.startPos, "cannot modify expression `%s` because it is a literal", format(node).ptr); 29: 389: if node.symbol do -: 390: { 44: 391: if var auto t = node.symbol.asType() do 5: 392: return error(scope.filename, node.startPos, "cannot modify type `%s`", format(node).ptr); 34: 393: if var auto vd = symToVarDecl(node.symbol) do 16: 394: if vd.isConst() do 14: 395: return error(scope.filename, node.startPos, "cannot modify expression `%s` because it is `const`", format(node).ptr); -: 396: } 20: 397: if var auto te = node.asTypeExp() do 1: 398: return error(scope.filename, node.startPos, "cannot modify type `%s`", format(te.type).ptr); 9: 399: error(scope.filename, node.startPos, "cannot modify expression `%s`", format(node).ptr); 9: 400: } -: 401: -: 402: function checkIfInvalidBinaryOnArray(BinaryExpression* node): bool -: 403: { 2409: 404: var auto tm1 = asTypePointer(node.left.type) || asTypeEnumSet(node.left.type) ? null else asTypeModified(node.left.type); 2409: 405: var auto tm2 = asTypePointer(node.right.type) || asTypeEnumSet(node.right.type) ? null else asTypeModified(node.right.type); 2409: 406: if tm1 || tm2 do -: 407: { 3: 408: error(scope.filename, node.startPos, "cannot use binary `%s` if operands are slices or arrays", tokenString[node.operator].ptr); 3: 409: setError(node); 3: 410: return true; -: 411: } 2406: 412: return false; -: 413: } -: 414: -: 415: /// Returns: if `node` is an invalid member for an EnumSetOperation -: 416: function checkIfInvalidEnumSetMember(var Expression* node; TypeEnumSet* tes): bool -: 417: { -: 418: // literal member 381: 419: if node.symbol && node.symbol.parent.astNode:u8* == tes.declaration:u8* do 308: 420: return false; -: 421: // whole set op 73: 422: if asTypeEnumSet(node.type) == tes do 18: 423: return false; -: 424: // exact member but value is not known 55: 425: var auto wt = asTypeEnum(tes.declaration.asTypeDeclared); 55: 426: var auto te = asTypeEnum(node.type); 55: 427: if te && te == wt do 47: 428: return false; -: 429: // array exp to convert to set 8: 430: var auto tsa = asTypeStaticArray(node.type); 8: 431: if tsa && asTypeEnum(tsa.modified) == tes.declaration.asTypeDeclared do -: 432: { 3: 433: node = castStaticArrayToEnumSet(node, tes, scope); 3: 434: return false; -: 435: } -: 436: // reject, incl. from extended enum as value may overflow base.max 5: 437: error(scope.filename, node.startPos, "`%s` does not give a valid `%s` member", format(node).ptr, format(wt).ptr); 5: 438: return false; -: 439: } -: 440: -: 441: /// Returns: if `node` is an invalid EnumSet operation -: 442: function checkIfInvalidEnumSetOp(BinaryExpression* node): bool -: 443: { 2620: 444: var auto tes = asTypeEnumSet(node.left.type); 2620: 445: if !tes do 2503: 446: return false; 117: 447: const auto op = node.operator; 117: 448: switch op do -: 449: { -: 450: on plusAss, minusAss, plus, minus do 115: 451: return checkIfInvalidEnumSetMember(node.right, tes); 2: 452: else do {} -: 453: } 2: 454: error(scope.filename, node.startPos, "only `+`, `-`, `in` and index operations are allowed on enum set `%s`", format(tes).ptr); 2: 455: setError(node); 2: 456: return true; -: 457: } -: 458: -: 459: /// Returns: if `node` is a pointer arithmetic operation -: 460: function checkPtrArithmeticOp(BinaryExpression* node): bool -: 461: { 2618: 462: if node.left.type && node.left.type.resolved().kind == mul do -: 463: { 209: 464: const auto yieldInt = asTypePointer(node.right.type) != null; 209: 465: const auto yieldPtr = node.right.type.isIntegral(); 209: 466: if (!yieldInt && !yieldPtr) || (node.operator != plus && node.operator != minus && node.operator != plusAss && node.operator != minusAss) do -: 467: { 1: 468: error(scope.filename, node.startPos, "cannot perform pointer arithmetic using the `%s` operator", tokenString[node.operator].ptr); 1: 469: setError(node); -: 470: } 208: 471: else do node.type = yieldInt ? TypeSSize() else node.left.type; 209: 472: return true; -: 473: } 2409: 474: return false; -: 475: } -: 476: -: 477: /// Verify that current function `this` type is correct for to access `node` member -: 478: function checkRightImplicitThis(Expression* node; Declaration* decl) -: 479: { 5152: 480: var auto fd = scope.func; 5152: 481: var auto t0 = decl.symbol.parentAggregate().asType(); 5152: 482: var Type* t1 = TypeError.instance(); 5152: 483: if fd && fd.parameters.length && fd.parameters[0].name == thisToken() do -: 484: { 10298: 485: if var auto tp = fd.parameters[0].type.asTypePointer() do 5149: 486: t1 = tp.modified.resolved(); -: 487: } 5152: 488: if t0 != t1 do -: 489: { 280: 490: if !inheritsOf(t1, t0) do -: 491: { 3: 492: error(scope.filename, node.startPos, "member `%s` is not static and cannot be accessed without `this`", decl.name.text().ptr); 3: 493: setError(node); -: 494: } -: 495: } 4872: 496: else do if fd do 9744: 497: if var auto vd = asVariableDeclaration(decl) do -: 498: { -: 499: // `struct S { var s32 m function f(s32 p = m){} }` -: 500: // would be technically possible but that is too much of a special case 3079: 501: if fd.progress == running && isInInitializer in scope.flags do 1: 502: error(scope.filename, node.startPos, "non-static member `%s` cannot be used as parameter default value", decl.name.text().ptr); -: 503: } 5152: 504: } -: 505: -: 506: @constructor function create(const Expression* node; const Scope* scope) -: 507: { 117106: 508: this.result = node; 117106: 509: this.scope = scope; 117106: 510: } -: 511: -: 512: /// Fix precedence in DotExps where the dot RHS expands to an ExpressionAlias -: 513: function dotExpressionAlias(DotExpression* node; ExpressionAlias* ea; Symbol* entryScopeSym) -: 514: { -: 515: import copyExpression in styx.ast.copier; -: 516: -: 517: var Expression* e; 18: 518: copyExpression(ea.expression, &e); 18: 519: e.startPos = node.dotted.startPos; 36: 520: if var auto ue = e:UnaryExpression* do -: 521: { -: 522: // e.g a CAllExp: `e1.e2` -> `e1.(e2.e3())` -> (e1.e2).e3() 22: 523: if var auto de = asDotExp(ue.expression) do -: 524: { 3: 525: var auto e1 = node.expression; 3: 526: var auto e2 = de.expression; 3: 527: var auto e3 = de.dotted; 3: 528: de.expression = e1; 3: 529: de.dotted = e2; 3: 530: node.expression = de; 3: 531: node.dotted = e3; -: 532: } -: 533: // e.g an IndexExp: `e1.e2` -> `e1.(e2[e3])` -> (e1.e2)[e3] -: 534: else do -: 535: { 8: 536: node.dotted = ue.expression; -: 537: } 11: 538: ue.expression = node; 11: 539: result = null; 11: 540: visitConcreteExpression(ue); 11: 541: result ?= ue; -: 542: } -: 543: // e.g a CmpExp: `e1.e2` -> `e1.(e2 == e3)` -> `(e1.e2) == e3` 14: 544: else do if var auto be = e:BinaryExpression* do -: 545: { 6: 546: scope.setSym(entryScopeSym); 6: 547: node.expression.type = null; 6: 548: node.expression.symbol = null; 6: 549: node.dotted = be.left; 6: 550: be.left = node; 6: 551: result = be; 6: 552: visitConcreteExpression(be); 6: 553: result ?= be; -: 554: } -: 555: // e.g an IdentExp: `e1.e2` -> `e1.(e2)` -: 556: else do -: 557: { 1: 558: node.dotted = e; 1: 559: visitDotExpression(node); -: 560: } 18: 561: } -: 562: -: 563: /// Perform `expressionSemantic` on `node.left` and `node.right` -: 564: function processBinaryOperands(BinaryExpression* node) -: 565: { 14953: 566: scope = scope.pushNested(); 14953: 567: node.left = expressionSemantic(node.left, scope); 14953: 568: scope = scope.pop(); -: 569: 14953: 570: scope = scope.pushNested(); 14953: 571: tryAddScopedEnum(node.right.startPos, node.left.type, scope); 14953: 572: node.right = expressionSemantic(node.right, scope); 14953: 573: scope = scope.pop(); 14953: 574: } -: 575: -: 576: /// Perform `expressionSemantic` on `node.expression` -: 577: function processUnaryOperand(UnaryExpression* node) -: 578: { 10782: 579: scope = scope.pushNested(); 10782: 580: node.expression = expressionSemantic(node.expression, scope); 10782: 581: scope = scope.pop(); 10782: 582: } -: 583: -: 584: static function setError(const Expression* node) -: 585: { 866: 586: node.type = TypeError.instance(); 866: 587: } -: 588: -: 589: /// Try to transform an ArrayExp made of a single range into an enum set, similarly to `castArrayLiteralToEnumSet`. -: 590: /// `[SomeEnum.member1 .. SomeEnum.member3]` -> [SomeEnum.member1, SomeEnum.member2, SomeEnum.member3] -: 591: function tryArrayOfRangeToEnumSet(ArrayExpression* node): bool -: 592: { 369: 593: if node.items.length != 1 do 265: 594: return false; 104: 595: var auto re = asRangeExp(node.items.ptr[0]); 104: 596: if !re do 101: 597: return false; -: 598: 3: 599: var auto te1 = asTypeEnum(re.left.type); 3: 600: var auto te2 = asTypeEnum(re.right.type); 3: 601: if te1 && te2 && te1.declaration:u8* == te2.declaration:u8* && 2: 602: EnumFlag.hasRoomForSet in te1.declaration.flags && 2: 603: EnumFlag.isOrdered in te1.declaration.flags do -: 604: { 2: 605: var auto em1 = symToEnumMember(re.left.symbol); 2: 606: var auto em2 = symToEnumMember(re.right.symbol); 2: 607: if em1 && em2 do -: 608: { 2: 609: const auto ts = (new TypeEnumSet).create(te1.declaration); 2: 610: const auto v1 = getIntLiteral(em1.value).value:u32; 2: 611: const auto v2 = getIntLiteral(em2.value).value:u32; 2: 612: const u64 shf = 64 - (v2 - v1 - 1); 2: 613: const u64 val = (u64.max >> shf) << v1; 2: 614: result = (new IntegerExpression).create(node.startPos, null, val, ts); 2: 615: return true; -: 616: } -: 617: } 1: 618: return false; -: 619: } -: 620: -: 621: /// Returns: if a call of type `(new RcArrayType)(initial_length)` can be -: 622: /// lowered to `(var TcArrayType __tmp; tmp.length = initial_length;)` -: 623: function tryRcArrayCtor(CallExpression* node): bool -: 624: { 12749: 625: var auto ne = asNewExp(node.expression); 12749: 626: if ne && node.arguments.length == 1 do -: 627: { 42: 628: if var auto tra = asTypeRcArray(ne.expression.type) do -: 629: { 21: 630: var auto p = node.startPos; 21: 631: var auto e = node.arguments.ptr[0]; 21: 632: e = expressionSemantic(e, scope); 21: 633: e = implicitConvTo(e, TypeUSize(), scope); 21: 634: var auto vd = createVariable(p, Token.generateIdentifier(), tra, scope, true); 21: 635: var auto id = varToIdentExp(vd); 21: 636: var auto sl = (new SetLengthExpression).create(id, e, TypeUSize(), true); 21: 637: var auto de = (new DeclExpression).create(p, vd, null, tra); 21: 638: result = (new TupleExpression).create(p, [de, sl, id]); 21: 639: result = (new IndexExpression).create(p, result, (new IntegerExpression).create(p, null, 2, TypeUSize())); 21: 640: result = expressionSemantic(result, scope); 21: 641: return true; -: 642: } -: 643: } 12728: 644: return false; -: 645: } -: 646: -: 647: /// Returns: if `node.right` has converted to `node.left.type` -: 648: function tryOneWayAssImplicitConv(AssignExpression* node): bool -: 649: { 10806: 650: if var auto maybeRight = implicitConvTo(node.right, node.left.type, scope) do -: 651: { 5343: 652: node.right = maybeRight; 5343: 653: node.type = node.left.type; 5343: 654: return true; -: 655: } 60: 656: setError(node); 60: 657: return false; -: 658: } -: 659: -: 660: /// Promote `node` type to `u8` if it's a `bool` -: 661: function tryPromoteBool(var Expression* node) -: 662: { 4098: 663: if isTypeBool(node.type) do 12: 664: node = (new CastExpression).create(node.startPos, node, TypeU8.instance(), CastKind.intExt, true); 4098: 665: } -: 666: -: 667: /// Returns: either if `node.right` has converted to `node.left.type` or the opposite. -: 668: function tryTwoWaysBinaryImplicitConv(BinaryExpression* node): bool -: 669: { 5717: 670: session.startGagging(); 11434: 671: if var auto maybeRight = implicitConvTo(node.right, node.left.type, scope) do -: 672: { 5537: 673: node.type = node.left.type; 5537: 674: node.right = maybeRight; -: 675: } 360: 676: else do if var auto maybeLeft = implicitConvTo(node.left, node.right.type, scope) do -: 677: { 175: 678: node.type = node.right.type; 175: 679: node.left = maybeLeft; -: 680: } -: 681: else do -: 682: { 5: 683: session.stopGagging(); 5: 684: error(scope.filename, node.startPos, "cannot find common type of expressions `%s` and `%s`", format(node.left).ptr, format(node.right).ptr); 5: 685: setError(node); 5: 686: return false; -: 687: } 5712: 688: session.stopGagging(); 5712: 689: return true; -: 690: } -: 691: -: 692: /// Returns: if `node` has been rewritten to a CallExp for an operator overload -: 693: function tryRewritingToOperatorOverload(Expression* node; Expression*[] args): bool -: 694: { 64778: 695: if var auto e = tryOperatorOverload(node, args) do -: 696: { 228: 697: session.startGagging(); 228: 698: scope = scope.pushNested(); 228: 699: result = expressionSemantic(e, scope); 228: 700: scope = scope.pop(); 228: 701: session.stopGagging(); 228: 702: if result && !isTypeError(result.type) do 226: 703: return true; 2: 704: result = node; -: 705: } 32163: 706: return false; -: 707: } -: 708: -: 709: /** Returns: if the AssignExp is of type `slice[] = elem`, which bypasses -: 710: usual binary type checks. */ -: 711: function trySliceElemAssign(AssignExpression* node): Expression* -: 712: { 4971: 713: var auto se = asSliceExp(node.left); 4971: 714: if !se || isTypeError(se.type) do 4937: 715: return null; -: 716: -: 717: // prefer the implicit string literal slicing for `slice[] = "str"` 37: 718: if asStringExp(node.right) do return null; -: 719: 31: 720: var auto elemt = node.right.type.resolved(); 31: 721: var auto tsa = asTypeStaticArray(elemt); 31: 722: var auto tsl = asTypeSlice(elemt); 31: 723: var auto tra = asTypeRcArray(elemt); 31: 724: if tsa || tsl || tra do 23: 725: return null; 8: 726: var auto targetTsl = asTypeSlice(node.left.type); 8: 727: var auto targett = targetTsl.modified.resolved(); -: 728: 8: 729: session.startGagging(); 8: 730: var auto e = implicitConvTo(node.right, targett, scope); 8: 731: session.stopGagging(); -: 732: 8: 733: if e do -: 734: { 7: 735: se.isElemAssign = true; 7: 736: se.assignRhs = e; 7: 737: return se; -: 738: } 1: 739: return null; -: 740: } -: 741: -: 742: /** Returns: if the AssignExp is of type `slice[] = array` */ -: 743: function trySliceFullAssign(AssignExpression* node): Expression* -: 744: { 4964: 745: var auto se = asSliceExp(node.left); 9901: 746: if !se do return null; 27: 747: se.assignRhs = node.right; 27: 748: return se; -: 749: } -: 750: -: 751: /// Returns: if `node` was of form `node.length ? = node.right` and finally rewritten as a SetLengthExp -: 752: function tryToSetLengthExp(AssignExpression* node): bool -: 753: { 5642: 754: var auto le = asLengthExp(node.left); 5642: 755: if !le do 5463: 756: return false; 179: 757: const auto k = le.expression.type.resolved().kind; 179: 758: if k == tkRca do -: 759: { 178: 760: const auto ec = session.startGagging(); 178: 761: checkIfAssignable(le.expression); 178: 762: if session.stopGagging() != ec do 1: 763: error(scope.filename, node.left.startPos, "cannot modify length of `%s` because it is `const`", format(le.expression).ptr); -: 764: var BinaryExpression* newLenExp; 178: 765: switch node.operator do -: 766: { 146: 767: on TokenType.ass,optAss do {} 1: 768: on TokenType.mulAss do newLenExp = new MulExpression; 1: 769: on TokenType.divAss do newLenExp = new DivExpression; 1: 770: on TokenType.modAss do newLenExp = new ModExpression; 1: 771: on TokenType.pipeAss do newLenExp = new OrExpression; 1: 772: on TokenType.ampAss do newLenExp = new AndExpression; 1: 773: on TokenType.xorAss do newLenExp = new XorExpression; 1: 774: on TokenType.lshiftAss do newLenExp = new LShiftExpression; 1: 775: on TokenType.rshiftAss do newLenExp = new RShiftExpression; 20: 776: on TokenType.plusAss do newLenExp = new AddExpression; 4: 777: on TokenType.minusAss do newLenExp = new SubExpression; -: 778: } -: 779: 178: 780: var auto t = TypeUSize(); 178: 781: var auto nle = newLenExp ? newLenExp.create(node.startPos, le, implicitConvTo(node.right, t, scope), t) 146: 782: else implicitConvTo(node.right, t, scope); 178: 783: result = (new SetLengthExpression).create(le.expression, nle, t, true); -: 784: 178: 785: return true; -: 786: } 1: 787: assert(k == tkSlice); 1: 788: error(scope.filename, node.left.startPos, "cannot modify length of slice `%s`", format(le.expression).ptr); 1: 789: setError(node); 1: 790: return true; -: 791: } -: 792: -: 793: function unaryNotSupportedOnTypeError(const UnaryExpression* node) -: 794: { 10: 795: error(scope.filename, node.startPos, "unary `%s` not allowed on `%s` of type `%s`", -: 796: tokenString[node.operator].ptr, format(node.expression).ptr, format(node.expression.type).ptr); 10: 797: return setError(node); -: 798: } -: 799: -: 800: @override function visitAddAssignExpression(const AddAssignExpression* node) -: 801: { 223: 802: visitBinaryAssignExpression(node); 223: 803: } -: 804: -: 805: @override function visitAddExpression(const AddExpression* node) -: 806: { 901: 807: visitBinaryExpression(node); 901: 808: } -: 809: -: 810: @override function visitAndAndExpression(AndAndExpression* node) -: 811: { 1272: 812: processBinaryOperands(node); 1272: 813: if tryRewritingToOperatorOverload(node, [node.left, node.right]) do 2: 814: return; 3809: 815: if var auto e = toCondition(node.left, scope) do node.left = e; 3808: 816: if var auto e = toCondition(node.right, scope) do node.right = e; 1270: 817: node.type = TypeBool.instance(); 1270: 818: } -: 819: -: 820: @override function visitAndAssignExpression(const AndAssignExpression* node) -: 821: { 8: 822: visitBinaryAssignExpression(node); 8: 823: } -: 824: -: 825: @override function visitAndExpression(const AndExpression* node) -: 826: { 24: 827: visitBinaryExpression(node); 24: 828: } -: 829: -: 830: @override function visitApplyExpression(ApplyExpression* node) -: 831: { 699: 832: const auto inCall = isResolvingCall in scope.flags; -: 833: // PostApplyExpression is parsed as a postfix. That means -: 834: // that the application of a DotExp is done on the whole chain. -: 835: // Such an application must actually only be done on the chain RHS -: 836: // because the LHS can be a parameter for a UFC call. Rewrite -: 837: // `a.b[c]` (already lowered to `apply(a.b, c)`) as `a.apply(b, c)` 699: 838: if inCall do 1058: 839: if var auto de = asDotExp(node.generic) do -: 840: { 227: 841: var auto od = de.dotted; 227: 842: node.generic = od; 227: 843: de.dotted = node; 227: 844: result = expressionSemantic(de, scope); 227: 845: return; -: 846: } -: 847: -: 848: // retrieve the generic declaration 472: 849: scope.flags -= isResolvingCall; 472: 850: assert(node.generic.operator != eopType); 472: 851: node.generic = expressionSemantic(node.generic, scope.pushNested()); -: 852: var Declaration* gd; 944: 853: if var auto t = node.generic.type.resolved():TypeDeclared* do 472: 854: gd = t.declaration.genericParameters ? t.declaration else null; 472: 855: if !gd do -: 856: { 1: 857: error(scope.filename, node.startPos, "`%s` does not resolve to a generic declaration", format(node.generic).ptr); 1: 858: return setError(node); -: 859: } 471: 860: foreach const auto p in gd.genericParameters.parameters do 681: 861: if p.valueType && p.valueType.progress != done do 5: 862: p.valueType = resolveType(p.valueType, gd.scope.pop()); -: 863: -: 864: // check arg count -: 865: var usize numP; -: 866: var usize pidx; 471: 867: foreach const auto p in gd.genericParameters.parameters do 681: 868: if !p.appliedType && !p.appliedExp do 672: 869: numP++; 471: 870: const auto numA = node.arguments.length; 471: 871: if numA > numP do -: 872: { 4: 873: if !numP do 1: 874: error(scope.filename, node.startPos, "generic application of `%s` is complete an no more arguments are allowed", format(gd).ptr); -: 875: else do 3: 876: error(scope.filename, node.startPos, "`%s` expects `1` up to `%d` argument(s) and not `%d`", format(gd).ptr, numP, numA); 4: 877: return setError(node); -: 878: } 467: 879: foreach (const auto i; var auto p) in gd.genericParameters.parameters do 471: 880: if !p.applied() do 467: 881: break pidx = i; -: 882: -: 883: // arguments sema 467: 884: var auto argSc = scope; 910: 885: if scope.func do while argSc.sym.kind != unamed do 225: 886: argSc = argSc.pop(); 467: 887: foreach (const auto i; var auto a) in node.arguments do -: 888: { -: 889: // wildcard for partial application 646: 890: if a.operator == dollar do -: 891: { 7: 892: if argSc.array do 1: 893: warn(argSc.filename, a.startPos, "`$` does not expand to `%s.length`, it is used for partial generic application", format(argSc.array).ptr); 7: 894: continue; -: 895: } 1278: 896: if var auto le = asLambdaExp(a) do 7: 897: le.isGenericArg = true; 639: 898: var auto te = asTypeExp(a); 753: 899: if te do te.raw = false; 639: 900: var auto asc = argSc.pushNested(); 639: 901: const auto j = pidx + i; 639: 902: if j < gd.genericParameters.parameters.length do 1278: 903: if var auto vt = gd.genericParameters.parameters[j].valueType do 305: 904: tryAddScopedEnum(a.startPos, vt, asc); 639: 905: a = expressionSemantic(a, asc); 1278: 906: if var auto ea = evaluate(a) do 382: 907: a = ea; 753: 908: if te do te.raw = true; -: 909: } 769: 910: if inCall do scope.flags += isResolvingCall; -: 911: -: 912: var Declaration* app; -: 913: -: 914: import copyGenericParameters, copy in styx.ast.copier; -: 915: -: 916: // prepare the generic parameters and associate them to the arguments 467: 917: var auto paramsCpy = copyGenericParameters(gd.genericParameters):GenericParameters*; 467: 918: var auto parr = paramsCpy.parameters[]; 467: 919: var auto aarr = node.arguments[]; 467: 920: while aarr && parr do -: 921: { -: 922: var Type* t; 650: 923: const auto plen = parr.length; 650: 924: const auto alen = aarr.length; 650: 925: var auto p = parr.ptr[0]; 650: 926: parr = parr.ptr[1 .. plen]; 650: 927: if p.appliedType || p.appliedExp do 4: 928: continue; 646: 929: var auto a = aarr.ptr[0]; 646: 930: aarr = aarr.ptr[1 .. alen]; 1334: 931: if var auto f = symToFuncDecl(a.symbol) do p.appliedExp = a; 1371: 932: else do if var auto te = asTypeExp(a) do p.appliedType = te.type; 441: 933: else do if symToEnumMember(a.symbol) do p.appliedExp = a; 886: 934: else do if var auto od = symToOverDecl(a.symbol) do p.appliedExp = a; 439: 935: else do if a.symbol && (t = a.symbol.asType()) do p.appliedType = t; 860: 936: else do if a.canInitialize() do p.appliedExp = a; 17: 937: else do if a.operator == dollar do continue; -: 938: else do -: 939: { 3: 940: error(scope.filename, a.startPos, "`%s` is not known at compile-time", format(a).ptr); 3: 941: return setError(node); -: 942: } 636: 943: if p.valueType do -: 944: { 305: 945: var auto appt = p.appliedType; 305: 946: p.appliedType = null; 305: 947: if !p.appliedExp do -: 948: { 1: 949: error(scope.filename, a.startPos, "value expected for parameter `%s` and not type `%s`", format(p).ptr, format(appt).ptr); 1: 950: return setError(node); -: 951: } 608: 952: if var auto ec = implicitConvTo(p.appliedExp, p.valueType, argSc) do 303: 953: p.appliedExp = ec; 1: 954: else do return setError(node); -: 955: } 634: 956: p.originalExp = a; -: 957: } -: 958: -: 959: // try to find an existing application with same arguments 462: 960: setGenericParametersLinkageName(paramsCpy); 462: 961: var auto appNext = gd; 462: 962: var auto lastApp = gd; 462: 963: const auto pcpyName = paramsCpy.linkageName[]; 462: 964: while (appNext = appNext.nextInstance) do -: 965: { 2940: 966: if appNext.genericParameters.linkageName[] == pcpyName do 224: 967: break app = appNext; -: 968: // where to store the new application 2716: 969: lastApp = appNext; -: 970: } -: 971: -: 972: // if not found then copy the full generic decl 462: 973: if !app do -: 974: { 238: 975: lastApp.nextInstance = app = copy(gd, true).asDeclaration(); 238: 976: app.genericParameters = paramsCpy; 238: 977: app.baseGeneric = gd; 238: 978: app.linkageName = (gd.baseGeneric ? gd).symbol.fqn(true).tokenChainText(); 238: 979: app.linkageName ~= paramsCpy.linkageName; -: 980: // https://gitlab.com/styx-lang/styx/-/issues/566 -: 981: // the name matters, e.g for aggregate static decls 238: 982: app.name = identifier((gd.baseGeneric ? gd).name.text() ~ paramsCpy.linkageName); -: 983: -: 984: import attachDeclarationImports in styx.semantic.imports; -: 985: import symbolizeDeclaration in styx.semantic.symbolize; -: 986: 238: 987: var auto oe = session.errorsCount(); 238: 988: symbolizeDeclaration(app, gd.scope.pop()); 238: 989: attachDeclarationImports(app); 238: 990: declarationSemantic(app, app.scope.pop()); 238: 991: if session.errorsCount() != oe do 5: 992: error(scope.filename, node.startPos, "while applying `%s`", format(gd).ptr); 238: 993: assert(gd.scope.sym.parent:u8* == app.scope.sym.parent:u8*); -: 994: } -: 995: 462: 996: node.type = app.asTypeDeclared; 462: 997: node.symbol = app.symbol; 462: 998: node.application = (new IdentExpression).create(node.startPos, app.name, node.type, node.symbol); 462: 999: scope.setSym(app.symbol); -:1000: //printf("%s\n", format(app/*, testMode*/).ptr); 462:1001: } -:1002: -:1003: @override function visitArrayExpression(ArrayExpression* node) -:1004: { -:1005: // automatically set, e.g `echo(getUnittests)` can return empty static arrays. -:1006: // in this case, `deduceArrayLiteralElementType()` cannot work 390:1007: if node.type do 3:1008: return; 387:1009: node.isStaticallyEvaluable = true; 387:1010: if !node.items.length do -:1011: { 18:1012: node.type = TypeEmptyArray.instance(); 18:1013: return; -:1014: } 369:1015: foreach var auto e in node.items do -:1016: { 46206:1017: var auto na = asArrayExp(e); 46225:1018: if na do na.parentArray = node; 46206:1019: scope = scope.pushNested(); 46206:1020: e = expressionSemantic(e, scope); 46206:1021: scope = scope.pop(); 46206:1022: if !e.isLiteral() && (!e.symbol || e.symbol.kind != SymbolKind.enumMember) do 174:1023: node.isStaticallyEvaluable = false; 46206:1024: if na && !na.isStaticallyEvaluable do 5:1025: node.isStaticallyEvaluable = false; -:1026: } 369:1027: if tryArrayOfRangeToEnumSet(node) do 2:1028: return; 367:1029: if !node.isStaticallyEvaluable && !scope.func do 4:1030: error(scope.filename, node.startPos, "the array contains elements that can only be evaluated in functions"); -:1031: // get elem type -:1032: var Type* et; 367:1033: var auto onlyTypeNull = true; 367:1034: foreach const auto e in node.items do -:1035: { 374:1036: if isTypeNull(e.type) do 10:1037: continue; 364:1038: onlyTypeNull = false; 364:1039: et = e.type.resolved(); 364:1040: break; -:1041: } -:1042: // NullExp must always be cast to something else 367:1043: if onlyTypeNull do 3:1044: et = (new TypePointer).create(TypeU8.instance()); -:1045: -:1046: // try the more derived common class type 367:1047: var auto tp = et.asTypePointer(); -:1048: var bool wasClassPtrs; 367:1049: if tp && asTypeClass(tp.modified) do -:1050: { 58:1051: var auto ets = (new Type*[+])(node.items.length); 58:1052: foreach (const auto i; var auto e) in node.items do 110:1053: ets[i] = e.type; 116:1054: if var auto t = commonClassPointerType(ets) do -:1055: { 31:1056: et = t; 31:1057: wasClassPtrs = true; 31:1058: foreach var auto e in node.items do 82:1059: e = (new CastExpression).create(e.startPos, e, t, e.operator == $null ? CastKind.nullCast else CastKind.bitCast, true); -:1060: } -:1061: } -:1062: -:1063: // otherwise standard impconv 703:1064: if !wasClassPtrs do foreach var auto e in node.items do -:1065: { 92244:1066: if var auto c = implicitConvTo(e, et, scope) do -:1067: { 46119:1068: e = c; 46119:1069: et = c.type.resolved(); -:1070: } 3:1071: else do break et = null; -:1072: } 367:1073: if !et do -:1074: { 3:1075: if node.items.length do 3:1076: error(scope.filename, node.startPos, "cannot determine the common type of the array elements"); 3:1077: return setError(node); -:1078: } 364:1079: var auto ie = (new IntegerExpression).create(node.startPos, null, node.items.length, TypeUSize()); 364:1080: var auto tsa = (new TypeStaticArray).create(et, ie); 364:1081: node.type = tsa; -:1082: // even if array is fully constant, it is usefull to have a hidden var to make things like [literla1, literla2, .. , literlaN][select_by_var] 364:1083: if !node.parentArray && scope.func && !node.asLvalue do -:1084: { 282:1085: var auto vd = createVariable(node.startPos, Token.generateIdentifier(), tsa, scope, true); 282:1086: var auto id = varToIdentExp(vd); 282:1087: var auto ae = (new AssignExpression).create(node.startPos, id, node, tsa); 282:1088: var auto de = (new DeclExpression).create(node.startPos, vd, ae, tsa, vd.symbol); 282:1089: node.asLvalue = vd; 282:1090: result = de; -:1091: } 364:1092: } -:1093: -:1094: @override function visitAsmExpression(AsmExpression* node) -:1095: { 15:1096: node.type = resolveType(node.returnType, scope); 15:1097: foreach var auto e in node.arguments do -:1098: { 7:1099: scope = scope.pushNested(); 7:1100: e = expressionSemantic(e, scope); 7:1101: scope = scope.pop(); -:1102: } 15:1103: if isTypeAuto(node.type) do 2:1104: error(scope.filename, node.startPos, "the return type of an `asm` expression cannot be `auto`"); 15:1105: } -:1106: -:1107: @override function visitAssignExpression(AssignExpression* node) -:1108: { 5122:1109: const auto oomk = getMacroOperatorKind(node); 5122:1110: switch oomk do -:1111: { -:1112: on OpOverloadKind.indexAssign do -:1113: { 254:1114: var auto ie = asIndexExp(node.left); 254:1115: scope = scope.pushNested(); 254:1116: ie.expression = expressionSemantic(ie.expression, scope); 254:1117: scope = scope.pop(); 254:1118: if tryRewritingToOperatorOverload(node, ie.expression ~ ie.indexes ~ node.right) do 3:1119: return; -:1120: } -:1121: on OpOverloadKind.sliceAssign do -:1122: { 36:1123: var auto se = asSliceExp(node.left); 36:1124: scope = scope.pushNested(); 36:1125: se.expression = expressionSemantic(se.expression, scope); 36:1126: scope = scope.pop(); 36:1127: var auto e = se.range ? [se.expression, se.range.left, se.range.right, node.right][] else [se.expression, node.right][]; 36:1128: if tryRewritingToOperatorOverload(node, e) do 2:1129: return; -:1130: } 4832:1131: else do {} -:1132: } -:1133: 5117:1134: processBinaryOperands(node); -:1135: 5117:1136: if tryRewritingToOperatorOverload(node, [node.left, node.right]) do 1:1137: return; 5116:1138: if tryToSetLengthExp(node) do 145:1139: return; 9942:1140: if var auto e = trySliceElemAssign(node) do -:1141: { 7:1142: result = e; 7:1143: return; -:1144: } -:1145: 4964:1146: tryOneWayAssImplicitConv(node); 4964:1147: checkIfAssignable(node.left); -:1148: 9928:1149: if var auto e = trySliceFullAssign(node) do -:1150: { 27:1151: result = e; 27:1152: return; -:1153: } 9874:1154: if var auto te = asTupleExp(node.left) do -:1155: { 17:1156: te.isAssignLhs = te.allLvalues; 17:1157: if !te.isAssignLhs do 1:1158: session.error(scope.filename, node.startPos, "cannot unpack tuple in `%s` because it contains rvalue(s)", format(te).ptr); -:1159: } 4937:1160: } -:1161: -:1162: @override function visitAtExpression(AtExpression* node) -:1163: { 409:1164: processUnaryOperand(node); 409:1165: if tryRewritingToOperatorOverload(node, [node.expression]) do 1:1166: return; -:1167: 816:1168: if var auto vd = symToVarDecl(node.expression.symbol) do 332:1169: vd.flags -= isImmediate; 408:1170: var auto t = node.expression.type.resolved(); 408:1171: var auto tp = (new TypePointer).create(t); 408:1172: var auto tf = asTypeFunction(t); 408:1173: if !node.expression.isLvalue() && !tf do -:1174: { 4:1175: error(scope.filename, node.startPos, "cannot take address of rvalue expression `%s`", format(node.expression).ptr); 4:1176: return setError(node); -:1177: } 808:1178: if var auto fd = symToFuncDecl(node.expression.symbol) do -:1179: { 38:1180: if fd.getAtLLVM() do 1:1181: error(scope.filename, node.startPos, "cannot take address of instrinsic functions"); -:1182: } 404:1183: node.type = tp; 404:1184: node.symbol = node.expression.symbol; 404:1185: } -:1186: -:1187: function visitBinaryAssignExpression(AssignExpression* node) -:1188: { 446:1189: processBinaryOperands(node); 446:1190: if tryRewritingToOperatorOverload(node, [node.left, node.right]) do 4:1191: return; 442:1192: if tryToSetLengthExp(node) do 32:1193: return; 410:1194: if checkIfInvalidEnumSetOp(node) do 1:1195: return; 409:1196: checkIfAssignable(node.left); 409:1197: if checkPtrArithmeticOp(node) do 51:1198: return; 358:1199: if checkIfInvalidBinaryOnArray(node) do 1:1200: return; 357:1201: tryOneWayAssImplicitConv(node); 357:1202: } -:1203: -:1204: @override function visitBinaryExpression(BinaryExpression* node) -:1205: { 2222:1206: processBinaryOperands(node); 2222:1207: if tryRewritingToOperatorOverload(node, [node.left, node.right]) do 10:1208: return; -:1209: // a+b and a*b are supposed to be commutative, do it for opover too then 2212:1210: if (node.operator == TokenType.plus || node.operator == TokenType.mul) && 1260:1211: tryRewritingToOperatorOverload(node, [node.right, node.left]) do 2:1212: return; 2210:1213: if checkIfInvalidEnumSetOp(node) do 1:1214: return; 2209:1215: if checkPtrArithmeticOp(node) do 158:1216: return; 2051:1217: if checkIfInvalidBinaryOnArray(node) do 2:1218: return; 2049:1219: tryPromoteBool(node.right); 2049:1220: tryPromoteBool(node.left); 2049:1221: tryTwoWaysBinaryImplicitConv(node); 2049:1222: } -:1223: -:1224: @override function visitBoolExpression(const BoolExpression* node) -:1225: { 1750:1226: node.type = TypeBool.instance(); 1750:1227: } -:1228: -:1229: @override function visitCallExpression(CallExpression* node) -:1230: { 12749:1231: var auto scopeFd = scope.func; -:1232: -:1233: // super() -> super.currentFunct() 12749:1234: if node.expression.operator == TokenType.$super && scopeFd do -:1235: { 93:1236: var auto id = (new IdentExpression).create(node.expression.startPos, scopeFd.name); 93:1237: node.expression = (new DotExpression).create(node.expression.startPos, node.expression, id); -:1238: } -:1239: 12749:1240: var auto sc2 = scope.pushNested(); 12749:1241: sc2.flags += ScopeFlag.isResolvingCall; 12749:1242: node.expression = expressionSemantic(node.expression, sc2); -:1243: 12749:1244: if tryRcArrayCtor(node) do 21:1245: return; -:1246: -:1247: // frame params sema requires the scope as it is on entry 12728:1248: var auto entrySc = scope.pushNested(); 12728:1249: var auto fdTemp = getFuncDeclForCall(node); -:1250: // parent enum inference is not allowed on member func -:1251: // due to how the context is passed (this.func() -> func(this)) 12728:1252: const auto tryScopedEnum = fdTemp?.isStatic(); 12728:1253: foreach (const auto i; var Expression* e) in node.arguments do -:1254: { 13867:1255: scope = scope.pushNested(); 13867:1256: if tryScopedEnum && i < fdTemp.parameters.length do 8302:1257: tryAddScopedEnum(e.startPos, fdTemp.parameters.ptr[i].type, scope); 13867:1258: e = expressionSemantic(e, scope); 13867:1259: scope = scope.pop(); -:1260: } -:1261: -:1262: // try overloads 12728:1263: if node.expression.symbol && ScopeFlag.isResolvingOverload !in scope.flags do 23566:1264: if var auto od = symToOverDecl(node.expression.symbol) do -:1265: { 256:1266: if od.progress == SemanticProgress.pending do 7:1267: declarationSemantic(od, od.scope); 256:1268: scope.flags += ScopeFlag.isResolvingOverload; 256:1269: var auto oldExp = node.expression; 256:1270: var auto oldArgs = node.arguments.dup; 256:1271: foreach const auto i in 0 .. 2 do -:1272: { 581:1273: if i == 0 do scope.flags += ScopeFlag.firstOverloadPass; 69:1274: else do scope.flags -= ScopeFlag.firstOverloadPass; 325:1275: foreach const auto m in od.members do -:1276: { 903:1277: scope = scope.pushNested(); 1806:1278: if var auto de = asDotExp(node.expression) do -:1279: { 143:1280: de.dotted = m; 143:1281: de.type = null; -:1282: } 760:1283: else do node.expression = m; 903:1284: const auto old = session.startGagging(); 903:1285: visitCallExpression(node); 903:1286: if session.stopGagging() == old do -:1287: { 254:1288: var auto fd = getFuncDeclForCall(node); 254:1289: if !fd.symbol.isVisibleFrom(scope.sym) do 2:1290: error(scope.filename, node.startPos, "function `%s` is not visible from here", fd.name.text().ptr); 254:1291: scope.flags -= [ScopeFlag.firstOverloadPass, ScopeFlag.isResolvingOverload]:ScopeFlags; 254:1292: return; -:1293: } -:1294: // unset first argument if it was added 649:1295: node.arguments = oldArgs; 649:1296: node.expression = oldExp; 649:1297: node.isThisAdded = false; -:1298: // unset the FD cache as it is tried first in getFuncDeclForCall() 649:1299: node.fd = null; 649:1300: scope = scope.pop(); -:1301: } -:1302: } 2:1303: scope.flags -= ScopeFlag.isResolvingOverload; 2:1304: return error(scope.filename, node.startPos, "overload `%s` does not contain a function suitable for the call", od.name.text().ptr); -:1305: } -:1306: 12472:1307: if !node.isOpOverRewrite && tryRewritingToOperatorOverload(node, node.expression ~ node.arguments) do 74:1308: return; -:1309: 12398:1310: var auto fd = getFuncDeclForCall(node); 12398:1311: if !fd do -:1312: { 16:1313: error(scope.filename, node.startPos, "`%s` is not a function and is not callable", format(node.expression).ptr); 16:1314: return setError(node); -:1315: } 12382:1316: if fd.progress != done do -:1317: { 38:1318: const auto oe = session.errorsCount(); 38:1319: declarationSemantic(fd, fd.scope.pop()); 38:1320: if fd.progress != done && session.errorsCount() != oe do 3:1321: return setError(node); -:1322: } 12379:1323: if fd.isGeneric() do -:1324: { 33:1325: if !(fd = tryGenericApplicationFromArg(fd, node, scope)) do -:1326: { 3:1327: error(scope.filename, node.startPos, "`%s` is a generic function and is not callable", format(node.expression).ptr); 3:1328: return setError(node); -:1329: } -:1330: } 12346:1331: else do if fd.scope && isInGeneric in fd.scope.flags do -:1332: { 2:1333: error(scope.filename, node.startPos, "`%s` is nested in a generic and is not callable", format(node.expression).ptr); 2:1334: return setError(node); -:1335: } 12374:1336: if fd.getAtNoReturn() do 10:1337: scope.currentStatement.containsNoReturn = true; -:1338: 12374:1339: var auto returnType = fd.returnType; 12374:1340: const auto pending = fd.progress == SemanticProgress.pending; 12374:1341: const auto runBodySemaForAuto = isTypeAuto(returnType) && fd.body; 12374:1342: const auto runBodySemaForVar = fd.isVar() && !fd.bodyDone; 12374:1343: const auto runBodySemaForGen = fd.genericParameters && !fd.bodyDone; 12374:1344: if pending do declarationSemantic(fd, fd.scope.pop()); 12374:1345: if pending || runBodySemaForAuto || runBodySemaForVar || runBodySemaForGen do -:1346: { -:1347: import bodySemantic in styx.semantic.bodies; 135:1348: bodySemantic(fd); 135:1349: returnType = fd.returnType; -:1350: } -:1351: 12374:1352: node.fd = fd; 12374:1353: node.type = returnType; 12374:1354: var auto noVarReturnType = returnType.resolved(); 24748:1355: if var auto ts = noVarReturnType.asSymbol() do 72:1356: scope.setSym(ts); 24604:1357: else do if var auto tp = asTypePointer(node.expression.type) do 318:1358: if var auto ts = tp.modified.resolved().asSymbol() do 159:1359: scope.setSym(ts); -:1360: 12374:1361: var auto parameters = fd.parameters; 12374:1362: var auto de = asDotExp(node.expression); 12374:1363: const auto isSuperDot = de && asSuperExp(de.expression); 12374:1364: const auto isCtor = FunctionFlag.isCtor in fd.flags; 12374:1365: if de do -:1366: { -:1367: var bool isVarParamPipe; -:1368: // if there's e1(p).e2() and that e1 is void then if p is passed to a lvalue param then try to pipe it 4830:1369: var auto ce1 = asCallExp(de.expression); 4830:1370: var auto fd1 = ce1?.getFuncDeclForCall(); 4830:1371: if fd1 && isTypeVoid(fd1.returnType) do -:1372: { 6:1373: if fd1.parameters.length && parameters.length && fd1.parameters[0].isVar() && 2:1374: fd1.parameters[0].type.resolved() == parameters[0].type.resolved() && 2:1375: node.arguments.length < parameters.length do -:1376: { 2:1377: node.arguments = ce1.arguments[0] ~ node.arguments; 2:1378: isVarParamPipe = true; -:1379: } -:1380: } -:1381: // if there's e1.e2() and that e2 is not a member then the call is UFCS-style 4830:1382: if !isVarParamPipe do -:1383: { -:1384: var bool isMemberVar; -:1385: var bool isMemberFunc; 4828:1386: const auto isFqn = de.expression.symbol && (de.expression.symbol.kind in unitKinds); 9656:1387: if var auto mvd = symToVarDecl(de.dotted.symbol) do 6:1388: isMemberVar = de.dotted.symbol.parent.kind in aggregateKinds; 9644:1389: else do if var auto mfd = symToFuncDecl(de.dotted.symbol) do 4822:1390: isMemberFunc = de.dotted.symbol.parent.kind in aggregateKinds; 4828:1391: if !isFqn && !isMemberVar && !isMemberFunc && de.expression.type do -:1392: { 327:1393: node.arguments = de.expression ~ node.arguments; 327:1394: node.expression = de.dotted; 327:1395: visitCallExpression(node); 327:1396: return; -:1397: } -:1398: } -:1399: } -:1400: -:1401: // cheat on the return type if it's a ctor 12047:1402: if isCtor do -:1403: { 732:1404: node.type = parameters[0].type; 732:1405: if de && de.expression.operator == TokenType.$new do 622:1406: node.expression = de.dotted; -:1407: } -:1408: -:1409: // set the hidden `this` argument 12047:1410: if parameters.length && parameters[0].name == thisToken() && !node.isThisAdded do -:1411: { 6004:1412: var auto p0 = parameters[0]; 6004:1413: node.checkThis = AdditionalCheck.thiscalls in session.additionalChecks; -:1414: // rewrite `agg.memberFunc()` -> `memberFunc(agg)`, but not for `super.memberFunc()` 6004:1415: if de && !isSuperDot do -:1416: { 3897:1417: var auto thisArg = de.expression; 3897:1418: var auto tp = asTypePointer(thisArg.type); -:1419: // exactly the right TypePointer 3897:1420: if tp do -:1421: { 3261:1422: node.arguments = thisArg ~ node.arguments; 3261:1423: node.expression = de.dotted; 3261:1424: node.isThisAdded = true; -:1425: } -:1426: // a value is passed instead of a pointer -:1427: else do -:1428: { -:1429: // ctor with a `this` arg that is not a pointer -> value type ctor. -:1430: // `ctor()` -> `var T __temp; ctor(&__tmp); __tmp;` 636:1431: var auto t = asTypePointer(p0.type).modified.resolved(); 636:1432: if isCtor && thisArg.type.resolved() == t do -:1433: { 45:1434: var auto vd = createVariable(node.startPos, Token.generateIdentifier(), t, scope, true); 45:1435: var auto id = varToIdentExp(vd); 45:1436: var auto ae = (new AtExpression).create(node.startPos, id, p0.type); 45:1437: node.arguments = ae ~ node.arguments; 45:1438: node.isThisAdded = true; 45:1439: visitCallExpression(node); 45:1440: node.type = t; 45:1441: node.isValueCtor = true; 45:1442: node.checkThis = false; 45:1443: scope.setSym(t.asSymbol()); 45:1444: return; -:1445: } -:1446: // fixup missing AtExp on the `this`: `call(value)` -> `call(&value)` 591:1447: else do if thisArg.isLvalue() do -:1448: { 589:1449: var auto att = (new TypePointer).create(thisArg.type.resolved()); 589:1450: thisArg = (new AtExpression).create(thisArg.startPos, thisArg, att); 589:1451: de.expression = thisArg; 589:1452: node.checkThis= false; 589:1453: thisArg.parens++; 589:1454: visitCallExpression(node); 589:1455: return; -:1456: } -:1457: else do -:1458: { 2:1459: var auto ta = asTypePointer(p0.type).modified.asTypeAggregate(); 2:1460: error(scope.filename, thisArg.startPos, "`%s` does not give a pointer to an instance of `%s`", format(thisArg).ptr, ta.declaration.name.text().ptr); 2:1461: return setError(node); -:1462: } -:1463: } -:1464: } -:1465: // a member func is called from a member func body, but w/o the `this.`. Add it as argument. 2107:1466: else do if scopeFd && scopeFd.parameters.length && scopeFd.parameters[0].name == thisToken() do -:1467: { 2091:1468: var auto tp1 = asTypePointer(scopeFd.parameters[0].type); 2091:1469: var auto tp2 = asTypePointer(p0.type); 2091:1470: if tp1 && tp2 && (tp1 == tp2 || inheritsOf(tp1.modified, tp2.modified)) do -:1471: { 2091:1472: var auto te = (new ThisExpression).create(node.startPos); 2091:1473: te.type = p0.type; 2091:1474: te.symbol = scopeFd.parameters[0].symbol; 2091:1475: var auto e = tp1 == tp2 ? te else (new CastExpression).create(node.startPos, te, tp2, CastKind.bitCast, true); 2091:1476: node.arguments = e ~ node.arguments; -:1477: //node.expression = de.dotted; 2091:1478: node.isThisAdded = true; 2091:1479: node.checkThis = false; -:1480: } -:1481: } -:1482: // The `this` param is already here but it's not a pointer. Add `&` 16:1483: else do if node.arguments.length do -:1484: { 14:1485: var auto a0 = node.arguments[0]; 14:1486: if isTypeNull(a0.type) do 1:1487: a0.type = p0.type; 13:1488: else do if !asTypePointer(node.arguments[0].type) do -:1489: { 5:1490: var auto att = (new TypePointer).create(node.arguments[0].type.resolved()); 5:1491: assert(a0.isLvalue(), "cannot take address of non pointer rvalue to make ths this param"); 5:1492: node.arguments[0] = (new AtExpression).create(a0.startPos, a0, att); 5:1493: node.isThisAdded = true; 5:1494: node.checkThis = false; -:1495: } -:1496: } -:1497: } -:1498: // deactivate nullthis checks if call is optional 11411:1499: if node.checkThis && node.arguments.length && node.arguments[0].asOptAccessExp() do 100:1500: node.checkThis = false; -:1501: -:1502: // devirtualize 11411:1503: if fd.virtualIndex != -1 do -:1504: { -:1505: // first arg is always the one that has for type `@final class` -:1506: // fd.symbol.thisType() can give the inherited, i.e not the `@final` one -:1507: // same for fd.parameters[0] which is the type to which arg[0] is converted to 1470:1508: var auto tp = node.arguments.length ? asTypePointer(node.arguments[0].type) else null; 1470:1509: var auto tc = tp ? asTypeClass(tp.modified) else null; 1470:1510: node.isDevirtualized = FunctionFlag.isFinal in fd.flags || (tc && tc.declaration.getAtFinal()) || isSuperDot; -:1511: } -:1512: 11411:1513: const auto isVariadic = FunctionFlag.isCeeVariadic in fd.flags; 11411:1514: const auto numParams = parameters.length; 11411:1515: var auto requiredParamCount = numParams; -:1516: 11411:1517: foreach (const auto i; var auto p) in parameters do 18519:1518: if p.initializer do 1128:1519: break requiredParamCount = i; -:1520: 11411:1521: expandTuples(node.arguments, 0); -:1522: var usize i; 11411:1523: while true do -:1524: { 29324:1525: if isVariadic && i == numParams do 444:1526: break; 28880:1527: const auto hasExplicitArg = i < node.arguments.length; 28880:1528: const auto hasArg = hasExplicitArg || i < numParams && parameters[i].initializer != null; 28880:1529: const auto hasTooMuchArgs = i >= numParams; 28880:1530: const auto hasFinished = i == node.arguments.length && i == numParams; -:1531: 28880:1532: if hasFinished do 10300:1533: break; 18580:1534: if !hasArg || hasTooMuchArgs do -:1535: { 28:1536: error(scope.filename, node.startPos, "`%s` expects %d argument(s) and not %d", -:1537: format(node.expression).ptr, requiredParamCount, node.arguments.length); 28:1538: return setError(node); -:1539: } -:1540: 18552:1541: var auto arg = i < node.arguments.length ? node.arguments[i] else parameters[i].initializer; 18552:1542: var auto prm = parameters[i]; 18552:1543: const auto apr = argToParam(prm, arg, entrySc); 18552:1544: switch apr.kind do -:1545: { -:1546: on ArgToParamKind.maybe_tup do -:1547: { 5:1548: var auto tt = asTypeTuple(arg.type); 5:1549: continue expandTuple(arg, node.arguments, tt, i); -:1550: } -:1551: on ArgToParamKind.yes_implicitConversion do -:1552: { -:1553: // conversion of the initializer is done in decl sema -:1554: //assert(i != node.arguments.length); 2715:1555: node.arguments[i] = apr.conv; -:1556: } -:1557: on ArgToParamKind.yes_exact do -:1558: { 15193:1559: if i == node.arguments.length do 664:1560: node.arguments.length += 1; 15193:1561: node.arguments[i] = arg; -:1562: } -:1563: on ArgToParamKind.no_constToVar do -:1564: { 2:1565: error(scope.filename, node.startPos, "cannot pass constant `%s` as argument to mutable `var` parameter `%s`", -:1566: format(arg).ptr, format(prm).ptr); 2:1567: return setError(node); -:1568: } -:1569: on ArgToParamKind.no_wrongType do -:1570: { -:1571: // impConv has already issued an error 634:1572: return setError(node); -:1573: } -:1574: on ArgToParamKind.no_exact do -:1575: { 1:1576: error(scope.filename, node.startPos, "parameter %d is `var` but the argument type does not match exactly", i); 1:1577: return setError(node); -:1578: } -:1579: on ArgToParamKind.no_lvalue do -:1580: { 1:1581: error(scope.filename, node.startPos, "parameter %d is `var` but the argument is not a lvalue", i); 1:1582: return setError(node); -:1583: } -:1584: on ArgToParamKind.no_static do -:1585: { 1:1586: error(scope.filename, node.startPos, "parameter %d only accepts static variables", i); 1:1587: return setError(node); -:1588: } -:1589: } 17908:1590: i++; -:1591: } -:1592: -:1593: // if return is not a simple value, turns it as a Lvalue 10744:1594: const auto isRetRcArray = returnType.asTypeRcArray(); 10744:1595: const auto isRetStArray = returnType.asTypeStaticArray(); 10744:1596: const auto isReturnToLvalue = isRetRcArray || ((!fd.isVar()) && 10275:1597: (ScopeFlag.isInInitializer !in scope.flags || scope.func) && 10266:1598: (isRetStArray|| 10264:1599: returnType.asTypeAggregate() || 10225:1600: returnType.asTypeSlice())); 10744:1601: if isReturnToLvalue do -:1602: { 488:1603: var auto returnVar = createVariable(node.startPos, Token.generateIdentifier(), returnType.resolved(), entrySc, isRetRcArray || isRetStArray); 488:1604: var auto ae = (new AssignExpression).create(node.startPos, varToIdentExp(returnVar), node, returnVar.type); 488:1605: result = (new DeclExpression).create(node.startPos, returnVar, ae, returnVar.type, returnVar.symbol); -:1606: } 10744:1607: } -:1608: -:1609: @override function visitCastExpression(CastExpression* node) -:1610: { 3414:1611: scope = scope.pushNested(); 3414:1612: node.toType = resolveType(node.toType, scope); 3414:1613: scope = scope.pop(); -:1614: 3414:1615: processUnaryOperand(node); -:1616: 3414:1617: node.type = node.toType; 3414:1618: node.symbol = node.expression.symbol; -:1619: -:1620: // extract overload using toType 6828:1621: if var auto od = symToOverDecl(node.symbol) do -:1622: { 11:1623: node.symbol = null; 11:1624: node.type = null; 11:1625: if od.progress == SemanticProgress.pending do 1:1626: declarationSemantic(od, scope); -:1627: 11:1628: var CallExpression* ce = (new CallExpression).create(node.startPos); 11:1629: foreach const auto e in od.members do -:1630: { 18:1631: ce.expression = e; 36:1632: if var auto fd = getFuncDeclForCall(ce) do -:1633: { 18:1634: if node.toType.resolved() == fd.symbol.asType().resolved() do -:1635: { 8:1636: ce.expression = null; -:1637: //ce.free(); 8:1638: result = e; 8:1639: return; -:1640: } -:1641: } -:1642: } 3:1643: result = (new NullExpression).create(node.startPos, TypeNull.instance()); 3:1644: return; -:1645: } -:1646: 3403:1647: const auto ck = getCastKind(node.expression, node.toType); 3403:1648: switch ck do -:1649: { -:1650: on invalid do 6:1651: error(scope.filename, node.startPos, "illegal cast"); -:1652: on same do -:1653: { 116:1654: node.expression.type = node.toType; 116:1655: result = node.expression; -:1656: } -:1657: on intExt, fpExt, intToFp do 674:1658: node.kind = ck; -:1659: on staticCastP, funRet do 14:1660: node.kind = bitCast; -:1661: on staticCastS do 1:1662: result = forceCast(node.expression, node.toType); -:1663: on nullCast do 9:1664: node.kind = ck; -:1665: on staElems do -:1666: { 8:1667: var auto ae = asArrayExp(node.expression); 8:1668: var auto de = asDeclExp(node.expression); 8:1669: if !ae && de do -:1670: { 8:1671: if var auto da = de.expression do 8:1672: if var auto as = asAssignExp(da) do 4:1673: ae = asArrayExp(as.right); -:1674: } 8:1675: result = castArrayLiteralElements(ae, asTypeStaticArray(node.toType), scope); -:1676: } -:1677: on staToESet do 2:1678: result = castStaticArrayToEnumSet(node.expression, asTypeEnumSet(node.toType), scope); -:1679: on staToPtr do 1:1680: node.kind = bitCast; -:1681: on intToEnum, intToSet do 2:1682: node.kind = bitCast; -:1683: on strToChar do 2:1684: result = (new IntegerExpression).create(node.startPos, null, asStringExp(node.expression).value.text()[0], node.toType); -:1685: on strToDyna, staToDyna, rcaToDyna do 802:1686: if var auto e = emptyArrayToSlice(node.expression, node.toType, scope) do 2:1687: result = e; -:1688: else do 399:1689: result = expressionSemantic((new SliceExpression).create(node.expression.startPos, node.expression), scope); -:1690: on strToRca, staToRca, dynaToRca do -:1691: { 8:1692: if var auto e = emptyArrayToSlice(node.expression, node.toType, scope) do 2:1693: node.expression = e; 4:1694: result = expressionSemantic((new RcaAssignExpression).create(node.startPos, node.expression), scope); -:1695: } -:1696: on strToSta do 1:1697: node.kind = ck; -:1698: on tupToElem do 1:1699: result = tupleToElement(node.expression, node.toType, scope); -:1700: on elemToTup do 2:1701: result = elementToTuple(node.expression, node.toType, scope); -:1702: on CastKind.tupToStruct do 8:1703: if var auto e = tupleToStruct(node.expression, node.toType, scope) 4:1704: do result = e; -:1705: -:1706: on opTrue do -:1707: { 3:1708: session.startGagging(); 3:1709: result = toCondition(node.expression, scope); 3:1710: session.stopGagging(); 3:1711: if !result do -:1712: { 1:1713: result = node; 1:1714: setError(node); 1:1715: continue on invalid; -:1716: } -:1717: } -:1718: on intTrunc, fpTrunc, fpToInt, bitCast, ptrCast do 2088:1719: node.kind = ck; -:1720: on dynCastP do -:1721: { 47:1722: node.kind = ck; 47:1723: var auto tc = asTypeClass(asTypePointer(node.toType).modified); 47:1724: if tc && !tc.declaration.vtable.length do 1:1725: error(scope.filename, node.startPos, "cannot dynamic cast to `%s` because it does not contain virtual functions", format(tc).ptr); -:1726: } -:1727: on dynCastS do 1:1728: error(scope.filename, node.startPos, "dynamic casts only allowed on pointers to classes"); -:1729: on intToPtr do 4:1730: node.kind = ck; -:1731: on toCond do 8:1732: result = toCondition(node.expression, scope); -:1733: on voidCast do 5:1734: node.kind = ck; -:1735: } 3403:1736: } -:1737: -:1738: @override function visitCmpExpression(CmpExpression* node) -:1739: { 3825:1740: processBinaryOperands(node); -:1741: 3825:1742: var auto e1t = node.left.type.resolved(); 3825:1743: var auto e2t = node.right.type.resolved(); 3825:1744: if isTypeError(e1t) || isTypeError(e2t) do 5:1745: return setError(node); -:1746: 3820:1747: var auto tes = asTypeEnumSet(e1t) ? asTypeEnumSet(e2t); -:1748: // always compare slices, so that ir-gen does not require special cases 3820:1749: if asTypeRcArray(e1t) || (asTypeStaticArray(e1t) && !tes) do -:1750: { 50:1751: var auto se = (new SliceExpression).create(node.left.startPos, node.left); 50:1752: node.left = expressionSemantic(se, scope); -:1753: } 3820:1754: if asTypeRcArray(e2t) || (asTypeStaticArray(e2t) && !tes) do -:1755: { 37:1756: var auto se = (new SliceExpression).create(node.right.startPos, node.right); 37:1757: node.right = expressionSemantic(se, scope); -:1758: } -:1759: -:1760: // signed cmp unsigned / unsigned cmp signed : promote signed if none of the operands is a literal 3820:1761: if !getIntLiteral(node.left) && !getIntLiteral(node.right) do -:1762: { 1312:1763: const auto e1s = e1t.isSigned(); 1312:1764: const auto e2s = e2t.isSigned(); 1312:1765: if e1t.isIntegral() && e2t.isIntegral() && e1t.size == e2t.size && e1s != e2s do -:1766: { 10:1767: if e1s && e1t.size != 64 do -:1768: { 6:1769: var auto t = e1t:u8* == TypeS8.instance():u8* ? TypeS16.instance() else e1t:u8* == TypeS16.instance():u8* ? TypeS32.instance() else TypeS64.instance(); 6:1770: warn(scope.filename, node.left.startPos, "`%s` promoted to a `%s` because it is compared to an unsigned value of same size", format(node.left).ptr, format(t).ptr); 6:1771: node.left = (new CastExpression).create(node.left.startPos, node.left, t, CastKind.intExt, true); -:1772: } 4:1773: else do if e2s && e2t.size != 64 do -:1774: { 1:1775: var auto t = e2t:u8* == TypeS8.instance():u8* ? TypeS16.instance() else e2t:u8* == TypeS16.instance():u8* ? TypeS32.instance() else TypeS64.instance(); 1:1776: warn(scope.filename, node.right.startPos, "`%s` promoted to a `%s` because it is compared to an unsigned value of same size", format(node.right).ptr, format(t).ptr); 1:1777: node.right = (new CastExpression).create(node.right.startPos, node.right, t, CastKind.intExt, true); -:1778: } -:1779: } -:1780: } -:1781: 3820:1782: var auto tp1 = asTypePointer(e1t); 3820:1783: var auto tp2 = asTypePointer(e2t); 3820:1784: var auto ta1 = asTypeAggregate(tp1 ? tp1.modified else e1t); 3820:1785: var auto ta2 = asTypeAggregate(tp2 ? tp2.modified else e2t); -:1786: // skip implicit conv as `@operator(a==b)` functions may allow comparing exp with unrelated types 3820:1787: const auto tryOverloads = ta1 || ta2; -:1788: -:1789: // for things like `if var auto a = ... do`, `if a do`, `if !a do` dont even try operator overloads -:1790: // as this is pointer comparison, even for pointer to aggregate 3820:1791: var auto tn1 = asNullExp(node.left); 3820:1792: var auto tn2 = asNullExp(node.right); 3820:1793: var auto neq = (tp2 && tn1) || (tp1 && tn2); -:1794: -:1795: // simple numeric or ptr comparisons -:1796: var bool canCompare; 3820:1797: if !tryOverloads && tryTwoWaysBinaryImplicitConv(node) do -:1798: { 3665:1799: node.type = TypeBool.instance(); 3665:1800: canCompare = true; 3665:1801: e1t = node.left.type.resolved(); 3665:1802: e2t = node.right.type.resolved(); -:1803: } 3820:1804: node.type = TypeBool.instance(); 3820:1805: if neq do -:1806: { 88:1807: tn1 ? tn1.type = e2t else tn2.type = e1t; 88:1808: return; -:1809: } -:1810: -:1811: // op overloads 3732:1812: if !canCompare && tryOverloads do -:1813: { -:1814: // for `!=` on two class ptr instances and if the rtl support is present -:1815: // then always use `==`, a NexExpression is added later to the result 120:1816: var auto tc1 = tp1 ? asTypeClass(tp1.modified) else null; 120:1817: var auto tc2 = tp2 ? asTypeClass(tp2.modified) else null; 120:1818: const auto actalOp = node.operator; 120:1819: const auto equalOrNot = actalOp == TokenType.equal || actalOp == TokenType.notEqual; 120:1820: const auto useObjectOpOver = equalOrNot && session.hasRtl && tc1 && tc2; 120:1821: if useObjectOpOver do 71:1822: node.operator = TokenType.equal; -:1823: -:1824: // try opover 120:1825: var auto opoverOk = tryRewritingToOperatorOverload(node, [node.left, node.right]); 120:1826: opoverOk ?= tryRewritingToOperatorOverload(node, [node.right, node.left]); 212:1827: if opoverOk do canCompare = true; -:1828: 120:1829: if opoverOk && useObjectOpOver do -:1830: { 71:1831: var auto id = (new IdentExpression).create(node.startPos, objEqualToken()); 71:1832: var CallExpression* cex = (new CallExpression).create(node.startPos, id); 71:1833: cex.arguments = [node.left, node.right]; 71:1834: result = cex; 71:1835: if actalOp == TokenType.notEqual do 16:1836: result = (new NotExpression).create(node.startPos, result); 71:1837: result = expressionSemantic(result, scope); -:1838: } 120:1839: if canCompare do 92:1840: return; 28:1841: if tp1 && tp2 && tp1 == tp2 do 19:1842: canCompare = true; -:1843: } -:1844: 3640:1845: node.buitlinCmpType = node.left.type.resolved().kind; -:1846: // verify builtin comparison based on memcmp 3640:1847: var auto tc = asTypeClass(node.left.type); 3640:1848: var auto ts = asTypeStruct(node.left.type); 3640:1849: var auto tu = asTypeUnion(node.left.type); 3640:1850: var auto tsa = asTypeStaticArray(node.left.type); 3640:1851: var auto tsl = asTypeSlice(node.left.type); 3640:1852: var auto tt = asTypeTuple(node.left.type); 3640:1853: if e1t == e2t && (tc || ts || tsa || tsl || tt) do -:1854: { 124:1855: const auto oe = session.errorsCount(); 124:1856: if node.operator > TokenType.notEqual do 1:1857: error(scope.filename, node.startPos, "can only use `==` and `!=` to compare non-basic types"); 124:1858: if !node.left.isLvalue() do 1:1859: error(scope.filename, node.left.startPos, "`%s` is not a lvalue but this is required to compare non-basic types", format(node.left).ptr); 124:1860: if !node.right.isLvalue() do 1:1861: error(scope.filename, node.right.startPos, "`%s` is not a lvalue but this is required to compare non-basic types", format(node.right).ptr); 124:1862: if oe == session.errorsCount() do 122:1863: canCompare = true; 124:1864: return; -:1865: } -:1866: // no memcmp on whole union 3516:1867: else do if tu do 1:1868: error(scope.filename, node.startPos, "cannot directly compare two unions, compare a specific member instead"); -:1869: // cannot compare if a variable of such type cant be declared 3515:1870: else do if e1t && !isTypeError(e1t) && !e1t.isVariableType() do 4:1871: error(scope.filename, node.startPos, "cannot compare `%s` because it has no value", format(e1t).ptr); 3511:1872: else do if e2t && !isTypeError(e2t) && !e2t.isVariableType() do 1:1873: error(scope.filename, node.startPos, "cannot compare `%s` because it has no value", format(e2t).ptr); 3512:1874: else do if !canCompare do error(scope.filename, node.startPos, "illegal comparison"); 3516:1875: } -:1876: -:1877: @override function visitConcatAssignExpression(ConcatAssignExpression* node) -:1878: { 807:1879: processBinaryOperands(node); 807:1880: if tryRewritingToOperatorOverload(node, [node.left, node.right]) do 1:1881: return; -:1882: 806:1883: var auto tra1 = asTypeRcArray(node.left.type); 806:1884: if !tra1 do -:1885: { 1:1886: error(scope.filename, node.startPos, "cannot append using `~=` on `%s` of type `%s`", format(node.left).ptr, format(node.left.type).ptr); 1:1887: return setError(node); -:1888: } -:1889: 805:1890: checkIfAssignable(node.left); -:1891: 805:1892: var auto tex = tra1.modified.resolved(); 805:1893: var auto t = node.right.type.resolved(); 805:1894: var auto tsa2 = asTypeStaticArray(t); 805:1895: var auto tsl2 = asTypeSlice(t); 805:1896: var auto tra2 = asTypeRcArray(t); 805:1897: var auto tp2 = asTypePointer(t); 805:1898: var auto tm2 = tp2 ? null else asTypeModified(t); 805:1899: var auto te = tsa2 || tsl2 || tra2 ? tm2.modified.resolved() else TypeError.instance(); 805:1900: var auto se = asStringExp(node.right); -:1901: -:1902: // string literal special case 805:1903: if !tm2 && se && isTypeS8(tex) && se.value.text().length > 1 do -:1904: { 140:1905: tm2 = (new TypeSlice).create(TypeS8.instance()); 140:1906: te = tex; -:1907: } -:1908: // elem 805:1909: if !tm2 do -:1910: { 238:1911: te = tex; 476:1912: if var auto e = implicitConvTo(node.right, tex, scope) do 235:1913: node.right = e; 3:1914: else do te = TypeError.instance(); -:1915: } -:1916: // elem is itself a rc array 567:1917: else do if tm2 == tex do -:1918: { 6:1919: te = tex; 6:1920: tm2 = null; -:1921: } -:1922: // expected elem is a nested rc array dim, given elem is a compatible slice 805:1923: var auto trc = asTypeRcArray(tex); 805:1924: if trc && tsl2 do -:1925: { 2:1926: te = tex; 4:1927: if var auto e = implicitConvTo(node.right, tex, scope) do -:1928: { 1:1929: node.right = e; 1:1930: tm2 = null; -:1931: } 1:1932: else do te = TypeError.instance(); -:1933: } 805:1934: if te != tex do -:1935: { 4:1936: error(scope.filename, node.startPos, "cannot append `%s` of type `%s` to `%s`", format(node.right).ptr, format(t).ptr, format(tra1).ptr); 4:1937: return setError(node); -:1938: } -:1939: 801:1940: node.type = tra1; -:1941: 801:1942: if tm2 do -:1943: { 559:1944: node.kind = ConcatKind.slice; 559:1945: if !tsl2 do -:1946: { 243:1947: node.right = (new SliceExpression).create(node.right.startPos, node.right); 243:1948: node.right = expressionSemantic(node.right, scope); -:1949: } -:1950: } 242:1951: else do if !node.right.isLvalue() do -:1952: { 189:1953: node.kind = ConcatKind.rvalue; 189:1954: node.asLvalue = createVariable(node.startPos, Token.generateIdentifier(), te, scope, false); -:1955: } 53:1956: else do node.kind = ConcatKind.lvalue; 801:1957: } -:1958: -:1959: @override function visitConcatExpression(ConcatExpression* node) -:1960: { 90:1961: processBinaryOperands(node); 90:1962: if tryRewritingToOperatorOverload(node, [node.left, node.right]) do 1:1963: return; -:1964: -:1965: // always concatenate slices to prevent special case during ir-gen 89:1966: if asTypeRcArray(node.left.type) do 9:1967: node.left = expressionSemantic((new SliceExpression).create(node.left.startPos, node.left), scope); 89:1968: if asTypeRcArray(node.right.type) do 23:1969: node.right = expressionSemantic((new SliceExpression).create(node.right.startPos, node.right), scope); -:1970: 89:1971: var auto t1 = node.left.type.resolved(); 89:1972: var auto tsl1 = asTypeSlice(t1); 89:1973: var auto tsa1 = asTypeStaticArray(t1); 89:1974: var auto tra1 = asTypeRcArray(t1); 89:1975: var auto tm1 = tsl1 || tsa1 || tra1 ? asTypeModified(t1) else null; 89:1976: t1 = tm1 ? tm1.modified.resolved() else t1; -:1977: 89:1978: var auto t2 = node.right.type.resolved(); 89:1979: var auto tsl2 = asTypeSlice(t2); 89:1980: var auto tsa2 = asTypeStaticArray(t2); 89:1981: var auto tra2 = asTypeRcArray(t2); 89:1982: var auto tm2 = tsl2 || tsa2 || tra2 ? asTypeModified(t2) else null; 89:1983: t2 = tm2 ? tm2.modified.resolved() else t2; -:1984: 89:1985: if tm1 && !tm2 do -:1986: { -:1987: // string literals are s8* but implicitly converts to s8[] or s8 if their len is one. -:1988: // The first branch tries the s8* to s8[]. The second tries s8* to s8 but also -:1989: // tries elem2 to elem1, when a string literal is not involved. 16:1990: var auto se = asStringExp(node.right); 16:1991: if se && se.value.text().length != 1 && isTypeS8(t1) do -:1992: { 9:1993: node.right = implicitConvTo(node.right, node.left.type.resolved(), scope); 9:1994: tsl2 = asTypeSlice(node.right.type); 9:1995: tm2 = tsl2; 9:1996: t2 = tsl2.modified.resolved(); -:1997: } 14:1998: else do if var auto econv = implicitConvTo(node.right, t1, scope) do -:1999: { 7:2000: node.right = econv; 7:2001: t2 = econv.type.resolved(); -:2002: } -:2003: } 73:2004: else do if tm2 && !tm1 do -:2005: { -:2006: // see upper comment 38:2007: var auto se = asStringExp(node.left); 38:2008: if se && se.value.text().length != 1 && isTypeS8(t2) do -:2009: { 12:2010: node.left = implicitConvTo(node.left, node.right.type.resolved(), scope); 12:2011: tsl1 = asTypeSlice(node.left.type); 12:2012: tm1 = tsl1; 12:2013: t1 = tsl1.modified.resolved(); -:2014: } 52:2015: else do if var auto econv = implicitConvTo(node.left, t2, scope) do -:2016: { 26:2017: node.left = econv; 26:2018: t1 = econv.type.resolved(); -:2019: } -:2020: } -:2021: 89:2022: var auto expectedType = resolveType((new TypeSlice).create(t1), scope).resolved(); -:2023: 89:2024: if !t1 || !t2 || isTypeError(t1) || isTypeError(t2) || t1 != t2 do -:2025: { 1:2026: error(scope.filename, node.startPos, "cannot concatenate `%s` and `%s` because their types are different", -:2027: format(node.right).ptr, format(node.left).ptr); 1:2028: return setError(node); -:2029: } -:2030: -:2031: // create the result 88:2032: var auto vd = createVariable(node.startPos, Token.generateIdentifier(), expectedType, scope, true); 88:2033: vd.startPos = node.startPos; 88:2034: node.type = vd.type; 88:2035: result = (new DeclExpression).create(node.startPos, vd, node, node.type); -:2036: -:2037: // reference to the result, e.g for .length, .ptr, etc. 88:2038: node.result = varToIdentExp(vd); -:2039: 88:2040: if tm1 do -:2041: { 51:2042: node.leftPtr = (new PtrExpression).create(node.left, (new TypePointer).create(tm1.modified.resolved()), true); 51:2043: node.leftLength = tsl1 || tra1 ? (new LengthExpression).create(node.left, true, TypeUSize()) else tsa1.lengthExp; 51:2044: node.isLeftMemCpy = true; -:2045: } 37:2046: else do node.leftLength = (new IntegerExpression).create(node.startPos, null, 1, TypeUSize()); -:2047: 88:2048: if tm2 do -:2049: { 70:2050: node.rightPtr = (new PtrExpression).create(node.right, (new TypePointer).create(tm2.modified.resolved()), true); 70:2051: node.rightLength = tsl2 || tra2 ? (new LengthExpression).create(node.right, true, TypeUSize()) else tsa2.lengthExp; 70:2052: node.isRightMemCpy = true; -:2053: } 18:2054: else do node.rightLength= (new IntegerExpression).create(node.startPos, null, 1, TypeUSize()); -:2055: 88:2056: var AddExpression* ae = (new AddExpression).create(node.startPos, node.leftLength, node.rightLength); 88:2057: visitAddExpression(ae); -:2058: 88:2059: var auto se = (new SetLengthExpression).create(node.result, ae, TypeUSize(), false); 88:2060: node.setLength = se; -:2061: 88:2062: var auto dest = (new PtrExpression).create(node.result, (new TypePointer).create(asTypeModified(node.type).modified.resolved()), true); 88:2063: node.destPtr = dest; 88:2064: } -:2065: -:2066: @override function visitConditionalExpression(ConditionalExpression* node) -:2067: { 558:2068: scope = scope.pushNested(); 558:2069: node.condition = expressionSemantic(node.condition, scope); 558:2070: scope = scope.pop(); 1116:2071: if var auto c = toCondition(node.condition, scope) do 555:2072: node.condition = c; -:2073: 558:2074: if !node.elseExpression do -:2075: { 76:2076: if var auto ce = node.condition:CmpExpression* do -:2077: { 37:2078: var auto le = asLengthExp(ce.left); 37:2079: node.elseExpression = node.thenExpression; 37:2080: node.thenExpression = le ? le.expression else ce.left; 37:2081: node.isShorthandSyntax = true; -:2082: } -:2083: else do -:2084: { -:2085: // Because the backend assumes something is cached in CmpExp.ir -:2086: // also this restriction does not matter because the short syntax is designed to select among two pointers 1:2087: error(scope.filename, node.startPos, "shorthand syntax of conditional expression only works on comparisons"); 1:2088: return setError(node); -:2089: } -:2090: } -:2091: 557:2092: scope = scope.pushNested(); 557:2093: node.thenExpression = expressionSemantic(node.thenExpression, scope); 557:2094: scope = scope.pop(); 557:2095: scope = scope.pushNested(); 557:2096: node.elseExpression = expressionSemantic(node.elseExpression, scope); 557:2097: scope = scope.pop(); -:2098: -:2099: // out of the scope of impConv: one is void, ignore the type of the other. 557:2100: if isTypeVoid(node.thenExpression.type) || isTypeVoid(node.elseExpression.type) do -:2101: { 9:2102: node.type = TypeVoid.instance(); 9:2103: return; -:2104: } -:2105: 548:2106: session.startGagging(); 1096:2107: if var auto e = implicitConvTo(node.elseExpression, node.thenExpression.type, scope) do -:2108: { 505:2109: session.stopGagging(); 505:2110: node.elseExpression = e; -:2111: } 86:2112: else do if var auto e = implicitConvTo(node.thenExpression, node.elseExpression.type, scope) do -:2113: { 17:2114: session.stopGagging(); 17:2115: node.thenExpression = e; 17:2116: if node.isShorthandSyntax do 6:2117: if var auto tc = toCondition(e, scope) do 3:2118: node.condition = tc; -:2119: } -:2120: else do -:2121: { 26:2122: session.stopGagging(); -:2123: var bool conv; 52:2124: if var auto t = commonClassPointerType([node.thenExpression.type, node.elseExpression.type]) do -:2125: { 22:2126: conv = true; 22:2127: node.thenExpression = (new CastExpression).create(node.thenExpression.startPos, node.thenExpression, t, node.thenExpression.operator == $null ? CastKind.nullCast else CastKind.bitCast, true); 22:2128: node.elseExpression = (new CastExpression).create(node.elseExpression.startPos, node.elseExpression, t, node.elseExpression.operator == $null ? CastKind.nullCast else CastKind.bitCast, true); 22:2129: if node.isShorthandSyntax do 8:2130: if var auto tc = toCondition(node.thenExpression, scope) do 4:2131: node.condition = tc; -:2132: } 26:2133: if !conv do -:2134: { 4:2135: setError(node); 4:2136: return error(scope.filename, node.startPos, "cannot find common type of expressions `%s` and `%s`", -:2137: format(node.thenExpression).ptr, format(node.elseExpression).ptr); -:2138: } -:2139: } 544:2140: node.type = node.thenExpression.type; 544:2141: var auto se1 = asSliceExp(node.thenExpression); 544:2142: var auto se2 = asSliceExp(node.elseExpression); 544:2143: if se1 && se2 && (asStringExp(se1.expression) || asStringExp(se2.expression)) do -:2144: { 8:2145: var auto vd = createVariable(node.startPos, Token.generateIdentifier(), node.type, scope, false); 8:2146: var auto ae = (new AssignExpression).create(node.startPos, varToIdentExp(vd), node, node.type); 8:2147: result = (new DeclExpression).create(node.startPos, vd, ae, node.type, vd.symbol); -:2148: } 544:2149: } -:2150: -:2151: @override function visitDeclaration(const Declaration* node) -:2152: { -:2153: assert(0); -:2154: } -:2155: -:2156: @override function visitDeleteExpression(DeleteExpression* node) -:2157: { 134:2158: scope = scope.pushNested(); 134:2159: node.expression = expressionSemantic(node.expression, scope); 134:2160: scope = scope.pop(); 134:2161: var auto tp = asTypePointer(node.expression.type); 134:2162: if !tp do -:2163: { 1:2164: setError(node); 1:2165: return error(scope.filename, node.startPos, "can only `delete` pointers, not `%s` of type `%s`", -:2166: format(node.expression).ptr, format(node.expression.type).ptr); -:2167: } 266:2168: if var auto ta = asTypeAggregate(tp.modified) do 130:2169: node.dtor = ta.declaration.defaultDtor; 133:2170: if node.deallocator do -:2171: { 4:2172: scope = scope.pushNested(); 4:2173: node.deallocator = expressionSemantic(node.deallocator, scope); 4:2174: scope = scope.pop(); 4:2175: var auto isDeallocator = false; 8:2176: if var FunctionDeclaration* fd = symToFuncDecl(node.deallocator.symbol) do -:2177: { 4:2178: const auto okStatic = fd.isStatic(); 4:2179: const auto okReturn = isTypeVoid(fd.returnType); 4:2180: const auto vd = fd.parameters.length == 1 ? fd.parameters[0] else null; 4:2181: const auto pt = vd ? asTypePointer(vd.type) else null; 4:2182: const auto okParam = vd && !vd.isVar() && pt && pt.modified:u8* == TypeU8.instance():u8*; 4:2183: isDeallocator = okStatic && okReturn && okParam; -:2184: } 4:2185: if !isDeallocator do 2:2186: error(scope.filename, node.startPos, "the deallocator argument must give a `static function(u8*)`"); -:2187: } 133:2188: node.type = TypeVoid.instance(); 133:2189: } -:2190: -:2191: @override function visitDerefExpression(DerefExpression* node) -:2192: { 1325:2193: processUnaryOperand(node); 1325:2194: if tryRewritingToOperatorOverload(node, [node.expression]) do 1:2195: return; -:2196: 1324:2197: var auto expressionType = node.expression.type.resolved(); 1324:2198: var auto tp = asTypePointer(expressionType); 1324:2199: if !tp do -:2200: { 3:2201: error(scope.filename, node.startPos, "cannot dereference expression `%s` of type `%s` because it is not a pointer", -:2202: format(node.expression).ptr, format(expressionType).ptr); -:2203: //var CallExpression* ce = asCallExp(node.expression); -:2204: //if ce && ce.expression.type.asTypePointer() do -:2205: // info(node, "maybe `(*%s)(...)` was meant ?", format(ce.expression)); 3:2206: return setError(node); -:2207: } 1321:2208: var auto dereferencedType = tp.modified.resolved(); 1321:2209: if asTypeFunction(dereferencedType) do -:2210: { 2:2211: error(scope.filename, node.startPos, "function pointers cannot be dereferenced"); 2:2212: return setError(node); -:2213: } 1319:2214: node.type = dereferencedType; 1319:2215: node.symbol = node.expression.symbol; 2638:2216: if var auto ts = node.type.asSymbol() do -:2217: { 291:2218: scope.setSym(ts); -:2219: } 1319:2220: } -:2221: -:2222: @override function visitDivAssignExpression(const DivAssignExpression* node) -:2223: { 49:2224: visitBinaryAssignExpression(node); 49:2225: } -:2226: -:2227: @override function visitDivExpression(const DivExpression* node) -:2228: { 276:2229: visitBinaryExpression(node); 276:2230: } -:2231: -:2232: @override function visitDollarExpression(DollarExpression* node) -:2233: { 212:2234: if var auto e = scope.array do -:2235: { 105:2236: if tryRewritingToOperatorOverload(node, [e]) do 1:2237: return; -:2238: 104:2239: var auto tsa = asTypeStaticArray(e.type); 104:2240: var auto tsl = asTypeSlice(e.type) ; 104:2241: var auto tra = asTypeRcArray(e.type) ; 104:2242: if tsa || tsl || tra do -:2243: { 102:2244: node.expression = tsa ? tsa.lengthExp else (new LengthExpression).create(e, false, TypeUSize()); 102:2245: node.type = node.expression.type; 102:2246: return; -:2247: } 4:2248: if var auto tt = asTypeTuple(e.type) do -:2249: { 1:2250: result = (new IntegerExpression).create(e.startPos, null, tt.types.length, TypeU32.instance()); 1:2251: return ; -:2252: } 3:2253: if e do if var auto ie = asIntegerExp(e) do -:2254: { 1:2255: result = e; 1:2256: return; -:2257: } -:2258: } -:2259: 1:2260: error(scope.filename, node.startPos, "no array in scope to expand `$`"); 1:2261: setError(node); 1:2262: } -:2263: -:2264: @override function visitDotExpression(DotExpression* node) -:2265: { 16379:2266: var auto entryScopeSym = scope.sym; -:2267: var bool isStraightMemberCall; -:2268: -:2269: // set TypeExpression in a valid state 32758:2270: if var auto te = asTypeExp(node.expression) do 470:2271: te.raw = false; -:2272: -:2273: // `a.b`, solve `a.` 16379:2274: if !node.expression.type do -:2275: { 16046:2276: const auto of = scope.flags; 16046:2277: scope.flags -= ScopeFlag.isResolvingCall; 16046:2278: node.expression = expressionSemantic(node.expression, scope); 16046:2279: scope.flags = of; -:2280: } -:2281: 16379:2282: scope.flags -= ScopeFlag.isInInitializer; 16379:2283: scope.flags += ScopeFlag.isDotDotted; -:2284: -:2285: // set TypeExpression that may have appeared due to a rewrite in a valid state 32758:2286: if var auto te = asTypeExp(node.expression) do 2169:2287: te.raw = false; -:2288: -:2289: // filter builtin properties 16379:2290: if node.dotted.operator == TokenType.id do 32302:2291: if var auto e = tryProperties(node, scope) do -:2292: { 2692:2293: scope.flags -= ScopeFlag.isDotDotted; 2692:2294: result = e; 2692:2295: return; -:2296: } -:2297: 13687:2298: assert(node.expression.type); -:2299: -:2300: // auto dereference of a aggregate ptr. a ptr itself has no member, but its deref does -:2301: // e.g for the DotExp `a.b` the intention is actually `(*a).b` 13687:2302: var auto tp = asTypePointer(node.expression.type); 27374:2303: if var auto tpa = tp ? asTypeAggregate(tp.modified) else null do 10256:2304: scope.setSym(tpa.declaration.symbol); -:2305: 13687:2306: if ScopeFlag.isResolvingCall in scope.flags && node.expression.operator != TokenType.$super do -:2307: { -:2308: // try `b` on `a.`, gag to allow trying UFCS 3916:2309: if scope.sym.kind in aggregateKinds do -:2310: { -:2311: // https://gitlab.com/styx-lang/styx/-/issues/243 -:2312: // call to a member func can launch sema of parent agg, -:2313: // be sure that parent agg errors are already discovered before gagging 7314:2314: if var auto ad = asTypeAggregate(scope.sym.asType()).declaration do 3657:2315: if ad.progress != SemanticProgress.done && !ad.isGeneric() do -:2316: assert(0); -:2317: 3657:2318: const auto g = session.startGagging(); 3657:2319: visitConcreteExpression(node.dotted); 3657:2320: isStraightMemberCall = session.stopGagging() == g; 7314:2321: if var auto ea = symToExpAlias(node.dotted.symbol) do 1:2322: isStraightMemberCall = true; -:2323: } -:2324: // try `b` on `a.`, `a` being a module 259:2325: else do if scope.sym.kind in unitKinds do -:2326: { 14:2327: isStraightMemberCall = true; 14:2328: visitConcreteExpression(node.dotted); -:2329: } -:2330: // failed, so restore the scope to the state before that `a.` was solved, as `a` may be a param. 4262:2331: if !isStraightMemberCall do scope.setSym(entryScopeSym); -:2332: } -:2333: 13687:2334: var auto t0 = asTypePointer(node.expression.type); 13687:2335: var auto ta = asTypeAggregate(t0 ? node.expression.type); 13687:2336: var auto id = asIdentExp(node.dotted); 13687:2337: const auto tryOpIdentifier = !isStraightMemberCall && id && ta && ta.declaration.canResolveIdentifiers; -:2338: // Handle member funcs of type `@operator(id) function opMember(s8[] identifier): auto;` 13687:2339: if tryOpIdentifier do -:2340: { 10:2341: const auto o = session.startGagging(); 10:2342: visitConcreteExpression(node.dotted); 10:2343: if o != session.stopGagging() do -:2344: { 9:2345: var auto se = (new StringExpression).create(id.startPos, id.identifier); 9:2346: var auto ts = (new TypeSlice).create(TypeS8.instance()); 9:2347: var auto ce = (new CastExpression).create(id.startPos, se, ts, CastKind.strToDyna); 9:2348: var auto e = expressionSemantic(ce, scope); 9:2349: if tryRewritingToOperatorOverload(node.dotted, [node.expression, e]) do 8:2350: return; -:2351: // show the error 1:2352: node.dotted.type = null; 1:2353: node.dotted.symbol = null; 1:2354: visitConcreteExpression(node.dotted); -:2355: } -:2356: } -:2357: // for a call : try to solve `b`, `a.` is ignored (it is not a "straight" call and instead maybe ufc) -:2358: // not a call : solve `b` wrt. to what `a.` was resolved to 13677:2359: else do if !isStraightMemberCall do -:2360: { 10107:2361: visitConcreteExpression(node.dotted); 20214:2362: if var auto gp = symToGenericParam(node.dotted.symbol) do -:2363: { 1:2364: result = gp.appliedExp; 1:2365: return; -:2366: } -:2367: // maintain the whole chain if `B` in `A.B` gives a TypeExp 10106:2368: if result do 20198:2369: if var auto te = asTypeExp(result) do -:2370: { 30:2371: node.dotted = te; 30:2372: result = node; -:2373: } -:2374: } -:2375: // Rewrite expression aliases to what is really intended 27356:2376: if var auto ea = symToExpAlias(node.dotted.symbol) do 18:2377: return dotExpressionAlias(node, ea, entryScopeSym); -:2378: -:2379: // `a.B` : `B` is a parent class of `a` type, e.g access parent field instead of `this` field 13660:2380: var auto tc0p = t0 ? asTypeClass(t0.modified.resolved()) else null; 13660:2381: var auto tc0v = asTypeClass(node.expression.type); 13660:2382: var auto tc0 = tc0v ? tc0p; 13660:2383: var auto tc1 = asTypeClass(node.dotted.type); 13660:2384: if tc0 && tc1 && inheritsOf(tc0, tc1) do -:2385: { 7:2386: if tc0v && !node.expression.isLvalue() do assert(0, "reopen #408, the fix does not work on rvalues"); 7:2387: scope.flags -= ScopeFlag.isDotDotted; 7:2388: result = tc0p ? implicitConvTo(node.expression, (new TypePointer).create(tc1), scope) 2:2389: else forceCast(node.expression, tc0v); 7:2390: return; -:2391: } -:2392: 13653:2393: node.type = node.dotted.type; 13653:2394: node.symbol = node.dotted.symbol; -:2395: 27306:2396: if var auto oae = asOptAccessExp(node.expression) do -:2397: { 165:2398: var auto ofd = symToFuncDecl(node.dotted.symbol); 165:2399: var auto rt = ofd ? ofd.returnType else node.type; 165:2400: if node.dotted.isLvalue() do 50:2401: oae.valueVar = createVariable(node.startPos, Token.generateIdentifier(), rt, scope, true); 165:2402: oae.valueType = rt; -:2403: } -:2404: 13653:2405: if node.symbol && node.expression.symbol do 24666:2406: if var auto t = node.expression.symbol.asType() do -:2407: { 1567:2408: if !asTypeEnum(t) do -:2409: { 524:2410: var auto vd = symToVarDecl(node.symbol); 524:2411: var auto fd = symToFuncDecl(node.symbol); 524:2412: const auto isNotStatic = (vd && !vd.isStatic()) || (fd && !fd.isStatic()); 524:2413: const auto isCtor = fd && fd.getAtConstructor(); 524:2414: if isNotStatic && !isCtor do -:2415: { 6:2416: error(scope.filename, node.startPos, "member `%s` is not static and cannot be accessed using type `%s`", -:2417: format(node.dotted).ptr, format(node.expression).ptr); -:2418: } -:2419: } -:2420: } -:2421: -:2422: // dont blindly check `a.someVar` 13653:2423: if dotvars in session.additionalChecks do 26496:2424: if var auto vd = symToVarDecl(node.dotted.symbol) do -:2425: { 8327:2426: const auto ta2 = asTypeAggregate(node.expression.type); -:2427: // `this.someVar` : check if nullthis-checks not enabled 8327:2428: const auto te = node.expression.operator == TokenType.$this; 8327:2429: const bool isThisChecked = thiscalls in session.additionalChecks && te; -:2430: // `(*a).someVar` : check 8327:2431: const auto de = node.expression.operator == ExtendedTokenType.eopDeref; -:2432: // `a?.b` : already explicitly checked 8327:2433: const auto oa = node.expression.operator == ExtendedTokenType.optAccess; 8327:2434: node.checkDotVar = !oa && (!ta2 || de) && !vd.isStatic() && !isThisChecked; -:2435: //printf("`%s` dotvar-check=%b\n", format(node).ptr, node.checkDotVar); -:2436: } -:2437: 13653:2438: scope.flags -= ScopeFlag.isDotDotted; 13653:2439: } -:2440: -:2441: @override function visitEchoExpression(const EchoExpression* node) -:2442: { 301:2443: foreach var auto a in node.arguments do -:2444: { -:2445: // allow "raw" type in echo 734:2446: if var auto te = asTypeExp(a) do 117:2447: te.raw = false; 367:2448: scope = scope.pushNested(); 367:2449: a = expressionSemantic(a, scope); 367:2450: scope = scope.pop(); -:2451: } 602:2452: if var auto e = evaluateEcho(node, scope) do -:2453: { 272:2454: result = e; 272:2455: visitConcreteExpression(e); -:2456: } 29:2457: else do node.type = TypeError.instance(); 301:2458: } -:2459: -:2460: @override function visitFloatExpression(FloatExpression* node) -:2461: { 120:2462: if node.tok do -:2463: { -:2464: import system; -:2465: 120:2466: errno = 0; 120:2467: const auto text = filterUnderscoresAndNullTerminate(node.tok); 120:2468: node.value = strtod(text.ptr, null); 120:2469: if errno != 0 do -:2470: { 1:2471: error(scope.filename, node.startPos, "cannot convert `%s` to `f64`", node.tok.text().ptr); 1:2472: setError(node); 1:2473: errno = 0; -:2474: } -:2475: } 120:2476: node.type = TypeF64.instance(); 120:2477: } -:2478: -:2479: @override function visitIdentExpression(IdentExpression* node) -:2480: { 60119:2481: if node.symbol do 161:2482: return; -:2483: -:2484: // try with() expressions. For each exp a strict search is tried, if the Ident is found -:2485: // then rewrite as a DotExp. 59958:2486: const auto wsLen = scope.withSyms.length; 59958:2487: if wsLen && ScopeFlag.isTryingWithSymbols !in scope.flags && ScopeFlag.isDotDotted !in scope.flags do -:2488: { 208:2489: foreach const auto we in scope.withSyms.ptr[0 .. wsLen] do 418:2490: if var auto s = we.searchSym.searchStrict(node.identifier, node.startPos, scope.sym) do -:2491: { 176:2492: var auto de = (new DotExpression).create(node.startPos, we.exp, node); 176:2493: scope.setSym(we.searchSym); 176:2494: scope.flags += ScopeFlag.isTryingWithSymbols; 176:2495: result = expressionSemantic(de, scope); 176:2496: scope.flags -= ScopeFlag.isTryingWithSymbols; 176:2497: return; -:2498: } -:2499: } -:2500: -:2501: var Symbol* s; -:2502: var Type* t; -:2503: // detect if this is the first epxression in a dot chain 59782:2504: var auto scFunc = scope.func; 59782:2505: var auto callSite = scFunc ? scFunc.symbol else scope.sym; 59782:2506: if scope.sym.kind in [SymbolKind.unamed, SymbolKind.$function, SymbolKind.$unit] do -:2507: { 45145:2508: s = scope.sym.searchWild(node.identifier, node.startPos, callSite); -:2509: } -:2510: else do -:2511: { 14637:2512: s = scope.sym.searchStrict(node.identifier, node.startPos, callSite); -:2513: // member init can refer to another member or to the outer scope, e.g -:2514: // `struct S { var T t = parentScope.stuff }` 14637:2515: if !s && ScopeFlag.isInInitializer in scope.flags do 26:2516: s = scope.sym.searchWild(node.identifier, node.startPos, callSite); -:2517: } 119564:2518: if var auto ad = symToAliasDecl(s) do -:2519: { 612:2520: const auto o = session.pauseGagging(); 612:2521: checkDeprecated(node, ad, scope); 612:2522: session.resumeGagging(o); 612:2523: getAliasee(ad, scope, t, s); -:2524: } 59782:2525: if s do -:2526: { 58350:2527: const auto o = session.pauseGagging(); 58350:2528: checkDeprecated(node, s.astNode, scope); 58350:2529: session.resumeGagging(o); -:2530: } -:2531: // found a unit, e.g qualified name 59782:2532: if s && s.kind in unitOrImportKinds do -:2533: { 48:2534: node.type = TypeVoid.instance(); 48:2535: node.symbol = s; 48:2536: scope.setSym(s); 48:2537: return; -:2538: } -:2539: // found a variable 119468:2540: if var auto vd = symToVarDecl(s) do -:2541: { 42047:2542: node.symbol = s; -:2543: // forward use of (opt auto) variable 42047:2544: if isTypeAuto(vd.type) || vd.progress == SemanticProgress.pending do 14:2545: declarationSemantic(vd, vd.scope); -:2546: // ad-hoc sema for parameter type that are TypeDeclared. -:2547: // In FuncDecl sema, this is skipped because of circular ref -:2548: // e.g in `function f(D* d){} struct D{ function e(){ f(this)} }` -:2549: // e body would not manage to match `f()` param with `this`. 84094:2550: if var auto tm = vd.type.mostModified() do 84094:2551: if var auto ts = tm.asSymbol() do 25216:2552: if ts.kind in needScopeKinds do 50416:2553: if var auto dws = ts.astNode.asDeclaration() do 25208:2554: if dws.progress == SemanticProgress.pending do -:2555: { 39:2556: declarationSemantic(dws, dws.scope); -:2557: } -:2558: 42047:2559: if isTypeError(vd.type) do 3:2560: return setError(node); 42044:2561: if vd.needThis() && (scope.sym.kind !in aggregateKinds || isInInitializer in scope.flags) do -:2562: { 3185:2563: if addThisExpForEscape(node, scope) do 8:2564: return; 3177:2565: checkRightImplicitThis(node, vd); -:2566: } -:2567: // manage use of escapes 42036:2568: if !vd.isStatic() && scFunc && (vd.scope.func && vd.scope.func != scFunc) || 41912:2569: (vd.isParameter && vd.symbol.parent != scFunc.symbol) do -:2570: { -:2571: // `this` in static nested function is for `this` type 124:2572: if scFunc.isStatic() && vd.name == thisToken() do -:2573: { 1:2574: s = scope.sym.parentAggregate(); 1:2575: result = (new TypeExpression).create(node.startPos, s.asType(), true); 1:2576: return; -:2577: } -:2578: else do -:2579: { 123:2580: if FunctionFlag.isNested !in scFunc.flags && vd.name != thisToken() do -:2581: { 2:2582: error(scope.filename, node.startPos, "cannot access variable `%s` in function `%s` because it is static", -:2583: node.identifier.text().ptr, scFunc.name.text().ptr); 2:2584: return setError(node); -:2585: } 121:2586: if FunctionFlag.isNested in vd.scope.func.flags do -:2587: { 1:2588: error(scope.filename, node.startPos, "cannot recover variable `%s` because it is declared in a nested function", node.identifier.text().ptr); 1:2589: return setError(node); -:2590: } 120:2591: vd.flags -= isImmediate; 120:2592: assert(node.isLvalue()); 120:2593: if vd.escapeIndex == -1 do -:2594: { 56:2595: vd.escapeIndex = vd.scope.func.escapes.length:u32; 56:2596: vd.scope.func.escapes ~= vd; -:2597: } 120:2598: vd.escapeUsed++; 120:2599: scFunc.flags += isReadingEscapes; -:2600: } -:2601: } 42032:2602: node.type = vd.type.resolved(); -:2603: // change scope for resolution of ident chains 84064:2604: if var auto ts = node.type.asSymbol() do -:2605: { 3409:2606: scope.setSym(ts); -:2607: } 38623:2608: else do if vd.name == thisToken() do -:2609: { 723:2610: var auto tp = asTypePointer(node.type); 723:2611: assert(tp, "hidden this parameter should be a pointer"); 723:2612: scope.setSym(tp.modified.resolved().asSymbol()); -:2613: } -:2614: // always set scope to resolved symbol, otherwise repetition of the last dotted exp would be accepted 37900:2615: else do scope.setSym(s); 42032:2616: return; -:2617: } -:2618: // found an enum member 35374:2619: if var auto em = symToEnumMember(s) do -:2620: { 2301:2621: var auto ed = symToEnumDecl(em.symbol.parent); 2301:2622: if ed.progress == SemanticProgress.pending do 1:2623: declarationSemantic(ed, ed.scope); 2301:2624: node.type = asTypeEnum(s.parent.asType()); 2301:2625: node.symbol = s; 2301:2626: scope.setSym(s); 2301:2627: return; -:2628: } -:2629: // found an anon enum 30772:2630: if var auto ed = symToEnumDecl(s) do -:2631: { 1151:2632: if ed && ed.progress == SemanticProgress.pending do 14:2633: declarationSemantic(ed, ed.scope); 1151:2634: if isEponymous in ed.flags do -:2635: { 198:2636: node.type = asTypeEnum(s.asType()); 198:2637: node.symbol = ed.members.ptr[0].symbol; 198:2638: scope.setSym(node.symbol); 198:2639: return; -:2640: } -:2641: } -:2642: // found a function 30376:2643: if var auto fd = symToFuncDecl(s) do -:2644: { 10366:2645: node.symbol = s; 10366:2646: if isTypeAuto(fd.returnType) || fd.progress == SemanticProgress.pending && fd.isStatic() do 177:2647: declarationSemantic(fd, fd.scope.pop()); 10366:2648: node.type = (new TypeFunction).create(fd, true); 10366:2649: if fd.needThis() && scope.sym.kind !in aggregateKinds do -:2650: { 1993:2651: if addThisExpForEscape(node, scope) do 18:2652: return; 1975:2653: checkRightImplicitThis(node, fd); -:2654: } 10348:2655: return; -:2656: } -:2657: // found an overload 9644:2658: if var auto od = symToOverDecl(s) do -:2659: { 252:2660: node.symbol = s; 252:2661: node.type = od.asTypeDeclared; 252:2662: return; -:2663: } -:2664: // found a generic parameter 9140:2665: if var auto gp = symToGenericParam(s) do -:2666: { 325:2667: t = null; 325:2668: if gp.appliedExp do -:2669: { -:2670: // if the application is accessed in a dotexp -:2671: // then the expression is extracted in visitDotExp 265:2672: node.symbol = s; 265:2673: node.type = gp.appliedExp.type; 265:2674: result = gp.appliedExp; 265:2675: return; -:2676: } 60:2677: if gp.appliedType do 60:2678: t = gp.appliedType; 60:2679: s = null; -:2680: } -:2681: // found an expression alias 8610:2682: if var auto ea = symToExpAlias(s) do -:2683: { -:2684: // because of postfixes, direct substitution would not give the intended expression -:2685: // in consequence this is done in visitDotExpression 20:2686: if isDotDotted in scope.flags do -:2687: { 18:2688: node.symbol = s; 18:2689: return; -:2690: } -:2691: import copyExpression in styx.ast.copier; -:2692: var Expression* e; 2:2693: copyExpression(ea.expression, &e); 2:2694: e.startPos = node.startPos; 2:2695: result = expressionSemantic(e, scope); 2:2696: return; -:2697: } -:2698: -:2699: // transforms "this" into its matching type, e.g to permit access to static aggregate members. 4285:2700: if !t do -:2701: { 3990:2702: if node.identifier == thisToken() && scFunc && scFunc.isStatic() do 6:2703: s = scope.sym.parentAggregate(); 3990:2704: t = s?.asType(); -:2705: } 4285:2706: if t do -:2707: { 5714:2708: if var auto ta = t.asTypeAggregate() do -:2709: { 1806:2710: if ta.declaration.progress != SemanticProgress.done do 157:2711: declarationSemantic(ta.declaration, ta.declaration.scope); 1806:2712: memulate(ta.declaration, ta.declaration.scope); -:2713: } -:2714: // callable functions are found earlier, here it's really a TypeFunction -:2715: // which can only be used for properties and echo(is). -:2716: // TypeDeclared need to be set as scope.sym, for exmplae to allow TypeDeclared.staticMember 2857:2717: if t.kind != TokenType.$function do 2826:2718: node.symbol = t.asSymbol(); 2857:2719: node.type = t.resolved(); -:2720: // change scope for resolution of type property / static member 2857:2721: if node.symbol do 2760:2722: scope.setSym(node.symbol); -:2723: // create a typeexp, so that it's possible to distinguish IndexExp and TypeStaticArray 2857:2724: result = (new TypeExpression).create(node.startPos, t, true); 2857:2725: result.symbol = node.symbol; 2857:2726: return; -:2727: } -:2728: -:2729: // finally, try parent enum inference 1428:2730: if ScopeFlag.isDotDotted !in scope.flags && scope.enumSym do 1255:2731: if (s = scope.enumSym.searchSym.searchStrict(node.identifier, node.startPos, scope.sym)) do -:2732: { 1255:2733: scope = scope.pushSym(scope.enumSym.searchSym); 1255:2734: visitIdentExpression(node); 1255:2735: return; -:2736: } -:2737: 173:2738: node.type = TypeError.instance(); 173:2739: error(scope.filename, node.startPos, "unrecognized identifier `%s`", node.identifier.text().ptr ); 173:2740: } -:2741: -:2742: @override function visitInExpression(InExpression* node) -:2743: { 176:2744: var auto e1o = asNotExp(node.right)?.expression; 176:2745: processBinaryOperands(node); 176:2746: if tryRewritingToOperatorOverload(node, [node.left, node.right]) do 2:2747: return; 174:2748: var auto tes = asTypeEnumSet(node.left.type); 186:2749: if !tes do if var auto tsa = asTypeStaticArray(node.left.type) do -:2750: { 4:2751: var auto te = asTypeEnum(tsa.modified); 4:2752: if te && isOrdered in te.declaration.flags do -:2753: { 4:2754: tes = (new TypeEnumSet).create(te.declaration); 4:2755: node.left = castStaticArrayToEnumSet(node.left, tes, scope); -:2756: } -:2757: } 174:2758: if tes do -:2759: { 172:2760: if e1o do -:2761: { 1:2762: var auto s1 = format(e1o).ptr; 1:2763: var auto s2 = format(node.left).ptr; 1:2764: error(scope.filename, node.startPos, "use `%s !in %s` to test for non-inclusion", s1, s2); -:2765: } 172:2766: node.type = TypeBool.instance(); 172:2767: checkIfInvalidEnumSetMember(node.right, tes); -:2768: } -:2769: else do -:2770: { 2:2771: error(scope.filename, node.startPos, "the `in` operator can only be used as operator overload and on enum sets"); 2:2772: return setError(node); -:2773: } 172:2774: } -:2775: -:2776: @override function visitIndexExpression(IndexExpression* node) -:2777: { 1324:2778: processUnaryOperand(node); -:2779: -:2780: var bool setInSet; 1324:2781: var auto tes = asTypeEnumSet(node.expression.type); 1324:2782: if tes do -:2783: { 94:2784: scope = scope.pushNested(); 94:2785: tryAddScopedEnum(node.startPos, tes, scope); -:2786: } 1324:2787: scope = scope.pushDollar(node.expression); 1324:2788: foreach var auto e in node.indexes do -:2789: { 1329:2790: scope = scope.pushNested(); 1329:2791: e = expressionSemantic(e, scope); 1329:2792: scope = scope.pop(); -:2793: } 1324:2794: if tes do -:2795: { 94:2796: scope = scope.pop(); 94:2797: setInSet = tes == node.indexes[0].type; -:2798: } 1324:2799: scope = scope.pop(); -:2800: 1324:2801: if tryRewritingToOperatorOverload(node, node.expression ~ node.indexes) do 9:2802: return; -:2803: -:2804: // Type[e] -> TypeExp 1315:2805: if node.indexes.length == 1 do 2626:2806: if var auto te = asTypeExp(node.expression) do -:2807: { 14:2808: var Type* t = (new TypeStaticArray).create(te.wrapped, node.indexes[0]); 14:2809: t = resolveType(t, scope); 14:2810: te.type = te.wrapped = t; 14:2811: te.symbol = null; 14:2812: result = te; 14:2813: return; -:2814: } -:2815: 2602:2816: if var auto tt = node.expression.type.asTypeTuple() do -:2817: { 103:2818: if node.indexes.length > 1 do 1:2819: error(scope.filename, node.startPos, "`%s` only supports a single index", format(tt).ptr); 103:2820: var auto i0 = node.indexes[0]; 206:2821: if var auto e = evaluate(i0) do 102:2822: node.indexes[0] = i0 = e; 103:2823: var auto ie = getIntLiteral(i0); 103:2824: if !ie do -:2825: { 1:2826: error(scope.filename, i0.startPos, "index `%s` does not give an integer literal", format(i0).ptr); 1:2827: return setError(node); -:2828: } 102:2829: if ie.value >= tt.types.length do -:2830: { 1:2831: error(scope.filename, i0.startPos, "`%d` is greater than the count of elements `%d`", ie.value, tt.types.length); 1:2832: return setError(node); -:2833: } 101:2834: node.arrayType = tt; 101:2835: node.type = tt.types[ie.value]; 101:2836: return; -:2837: } -:2838: 1198:2839: var auto indexedType = node.expression.type.asTypeModified(); 1198:2840: if !indexedType do -:2841: { 3:2842: error(scope.filename, node.startPos, "cannot index an element from type `%s` because it is not an array", -:2843: format(node.expression.type).ptr); 3:2844: return setError(node); -:2845: } 1195:2846: node.arrayType = indexedType; 1195:2847: if node.indexes.length > 1 do 1:2848: error(scope.filename, node.startPos, "`%s` only supports a single index", format(indexedType).ptr); 1195:2849: var auto index = node.indexes[0]; 1195:2850: if !index.type.isIntegral() && !isTypeBool(index.type) && !setInSet do -:2851: { 2:2852: error(scope.filename, node.startPos,"index must be of an integer type and not `%s`", format(index.type).ptr); 2:2853: return setError(node); -:2854: } 2386:2855: if var auto tsa = asTypeStaticArray(indexedType) do -:2856: { 262:2857: var auto ie0 = getIntLiteral(node.indexes[0]); 262:2858: var auto ie1 = getIntLiteral(tsa.lengthExp); 262:2859: if ie0 && ie1 do -:2860: { 153:2861: if ie0.value >= ie1.value do 1:2862: error(scope.filename, node.startPos,"index `%d` >= array length `%d`", ie0.value, ie1.value); -:2863: } 109:2864: else do node.sourceLength = tsa.lengthExp; 262:2865: node.expression = (new PtrExpression).create(node.expression, (new TypePointer).create(tsa.modified.resolved()), false); -:2866: } -:2867: else do -:2868: { 931:2869: var TypeModified* tm = asTypeSlice(indexedType); 931:2870: tm = tm ? asTypeRcArray(indexedType); 931:2871: if tm do -:2872: { 492:2873: node.sourceLength = (new LengthExpression).create(node.expression, true, TypeUSize()); 492:2874: node.expression = (new PtrExpression).create(node.expression, (new TypePointer).create(tm.modified.resolved()), false); -:2875: } -:2876: } 1193:2877: if tes do -:2878: { 94:2879: checkIfInvalidEnumSetMember(node.indexes[0], tes); 94:2880: if !setInSet do -:2881: { 93:2882: const auto te = tes.declaration.asTypeDeclared; 186:2883: if var auto econv = implicitConvTo(node.indexes[0], te, scope) do 92:2884: node.indexes[0] = econv; -:2885: } 94:2886: node.type = TypeBool.instance(); // set[member] = true | false | 1 | 0 -:2887: } -:2888: else do -:2889: { 1099:2890: node.type = indexedType.modified.resolved(); 2198:2891: if var auto ts = node.type.asSymbol() do 26:2892: scope.setSym(ts); -:2893: } 1193:2894: } -:2895: -:2896: @override function visitIntegerExpression(IntegerExpression* node) -:2897: { 19800:2898: if const auto tok = node.tok do -:2899: { -:2900: var u32 base; -:2901: var u32 offs; 9897:2902: switch tok.type do -:2903: { 1:2904: on TokenType.binLiteral do (base, offs) = (2, 2); 9642:2905: on TokenType.intLiteral do (base, offs) = (10, 0); 254:2906: on TokenType.hexLiteral do (base, offs) = (16, 2); -:2907: else do assert(0); -:2908: } -:2909: -:2910: import strToU64 in system; 9897:2911: if !strToU64(tok.text()[offs .. $], base, node.value) do -:2912: { 1:2913: error(scope.filename, node.startPos, "cannot convert `%s` to `u64`", tok.text().ptr); 1:2914: setError(node); -:2915: } -:2916: } 9900:2917: node.type = node.value <= u32.max ? TypeU32.instance() else TypeU64.instance(); 9900:2918: } -:2919: -:2920: @override function visitLShiftAssignExpression(const LShiftAssignExpression* node) -:2921: { 3:2922: visitBinaryAssignExpression(node); 3:2923: } -:2924: -:2925: @override function visitLShiftExpression(const LShiftExpression* node) -:2926: { 8:2927: visitBinaryExpression(node); 8:2928: } -:2929: -:2930: @override function visitLambdaExpression(LambdaExpression* node) -:2931: { -:2932: import bodySemantic in styx.semantic.bodies; -:2933: import symbolizeDeclaration in styx.semantic.symbolize; -:2934: 24:2935: symbolize(node.func, scope); 24:2936: declarationSemantic(node.func, scope); 24:2937: bodySemantic(node.func); 24:2938: checkEscapeUsed(node.func, true); 24:2939: node.func.flags += isInlineMaybe; -:2940: 24:2941: result = (new IdentExpression).create(node.startPos, node.func.name, node.func.asTypeDeclared, node.func.symbol); 24:2942: if !node.isGenericArg do -:2943: { 17:2944: var auto tp = (new TypePointer).create(node.func.asTypeDeclared); 17:2945: var auto at = (new AtExpression).create(node.startPos, result, tp); 17:2946: at.symbol = node.func.symbol; 17:2947: node.type = node.func.asTypeDeclared; 17:2948: node.symbol = result.symbol; 17:2949: result = at; -:2950: } 24:2951: } -:2952: -:2953: @override function visitModAssignExpression(const ModAssignExpression* node) -:2954: { 3:2955: visitBinaryAssignExpression(node); 3:2956: } -:2957: -:2958: @override function visitModExpression(const ModExpression* node) -:2959: { 60:2960: visitBinaryExpression(node); 60:2961: } -:2962: -:2963: @override function visitMulAssignExpression(const MulAssignExpression* node) -:2964: { 9:2965: visitBinaryAssignExpression(node); 9:2966: } -:2967: -:2968: @override function visitMulExpression(MulExpression* node) -:2969: { 410:2970: if node.right do -:2971: { 368:2972: visitBinaryExpression(node); 368:2973: return; -:2974: } 42:2975: var auto te = asTypeExp(node.left); 44:2976: if te do te.raw = false; 42:2977: var auto e = expressionSemantic(node.left, scope.pushNested()); 42:2978: if (te ? te = asTypeExp(e)) do -:2979: { 41:2980: var auto tp = (new TypePointer).create(te.wrapped); 41:2981: var auto tr = resolveType(tp, scope); 41:2982: te.type = te.wrapped = tr; 41:2983: te.raw = true; 41:2984: te.symbol = null; 41:2985: result = te; 41:2986: return; -:2987: } 1:2988: setError(node); 1:2989: } -:2990: -:2991: @override function visitNegExpression(NegExpression* node) -:2992: { 266:2993: processUnaryOperand(node); 266:2994: const auto ne = node.expression; 266:2995: if tryRewritingToOperatorOverload(node, [ne]) do 1:2996: return; -:2997: 265:2998: node.type = ne.type; 265:2999: node.symbol = ne.symbol; 265:3000: const auto isIntegral = ne.type.isIntegral(); 265:3001: const auto isFloating = ne.type.isFloating(); 265:3002: if !isIntegral && !isFloating do 2:3003: return unaryNotSupportedOnTypeError(node); 263:3004: if isIntegral do -:3005: { 257:3006: switch node.type.resolved().size do -:3007: { 1:3008: on 8 do node.type = TypeS8.instance(); 1:3009: on 16 do node.type = TypeS16.instance(); 253:3010: on 32 do node.type = TypeS32.instance(); 2:3011: on 64 do node.type = TypeS64.instance(); -:3012: } -:3013: } 263:3014: if ne.isLiteral() do 249:3015: result = evaluate(node); 263:3016: } -:3017: -:3018: @override function visitNewExpression(NewExpression* node) -:3019: { 1428:3020: if var auto te = asTypeExp(node.expression) do 9:3021: te.raw = false; 714:3022: scope = scope.pushNested(); 714:3023: node.expression = expressionSemantic(node.expression, scope); 714:3024: scope = scope.pop(); 1428:3025: if var auto te = asTypeExp(node.expression) do 712:3026: te.raw = true; 714:3027: var auto targetType = node.expression.type.resolved(); 714:3028: var auto ta = asTypeAggregate(targetType); 714:3029: if ta do 688:3030: memulate(ta.declaration, ta.declaration.scope); 714:3031: if targetType.size == 0 do -:3032: { 1:3033: error(scope.filename, node.startPos, "cannot use `new` for type `%s` because it has no size", format(targetType).ptr); 1:3034: return setError(node); -:3035: } 713:3036: if node.allocator do -:3037: { 4:3038: scope = scope.pushNested(); 4:3039: node.allocator = expressionSemantic(node.allocator, scope); 4:3040: scope = scope.pop(); 4:3041: var auto isAllocator = false; 8:3042: if var FunctionDeclaration* fd = symToFuncDecl(node.allocator.symbol) do -:3043: { 4:3044: const auto tp = asTypePointer(fd.returnType); 4:3045: const auto okStatic = fd.isStatic(); 4:3046: const auto okReturn = tp && tp.modified:u8* == TypeU8.instance():u8*; 4:3047: const auto vd = fd.parameters.length == 1 ? fd.parameters[0] else null; 4:3048: const auto okParam = vd && vd.type.isIntegral() && vd.type.size > 16 && !vd.isVar(); 4:3049: isAllocator = okStatic && okReturn && okParam; -:3050: } 4:3051: if !isAllocator do 2:3052: error(scope.filename, node.startPos, "the allocator argument must give a `static function(usize p): u8*`"); -:3053: } 713:3054: node.type = (new TypePointer).create(targetType); 713:3055: } -:3056: -:3057: @override function visitNotExpression(NotExpression* node) -:3058: { 1169:3059: processUnaryOperand(node); 1169:3060: if tryRewritingToOperatorOverload(node, [node.expression]) do 2:3061: return; -:3062: 1167:3063: const auto isIntegral = node.expression.type.isIntegral(); 1167:3064: const auto isFloating = node.expression.type.isFloating(); 1167:3065: const auto asPtr = asTypePointer(node.expression.type); 1167:3066: var auto isBool = isTypeBool(node.expression.type); -:3067: 1167:3068: node.type = node.expression.type; 1167:3069: node.symbol = node.expression.symbol; -:3070: 1167:3071: if !isIntegral && !isFloating && !asPtr && !isBool do -:3072: { 7:3073: const auto o = session.startGagging(); 14:3074: if var auto e = toCondition(node.expression, scope) do -:3075: { 6:3076: node.expression = e; 6:3077: node.type = TypeBool.instance(); 6:3078: isBool = true; -:3079: } 7:3080: if session.stopGagging() == o do 6:3081: node.type = node.expression.type; 1:3082: else do return unaryNotSupportedOnTypeError(node); -:3083: } -:3084: 1166:3085: if asPtr do -:3086: { 613:3087: result = (new CmpExpression).create(node.startPos, TokenType.equal, node.expression, (new NullExpression).create(node.startPos, asPtr), TypeBool.instance()); -:3088: } 553:3089: else do if node.expression.isLiteral() do -:3090: { 40:3091: result = evaluate(node); -:3092: } 513:3093: else do if isIntegral || isFloating do -:3094: { 102:3095: node.expression = toCondition(node.expression, scope); 102:3096: node.type = node.expression.type; -:3097: } 1166:3098: } -:3099: -:3100: @override function visitNullExpression(const NullExpression* node) -:3101: { 967:3102: node.type = TypeNull.instance(); 967:3103: } -:3104: -:3105: @override function visitOneCompExpression(OneCompExpression* node) -:3106: { 13:3107: processUnaryOperand(node); 13:3108: const auto ne = node.expression; 13:3109: if tryRewritingToOperatorOverload(node, [ne]) do 1:3110: return; -:3111: 12:3112: node.type = ne.type; 12:3113: node.symbol = ne.symbol; -:3114: 12:3115: if !ne.type.isIntegral() do 4:3116: return unaryNotSupportedOnTypeError(node); 8:3117: if ne.isLiteral() do 3:3118: result = evaluate(node); 8:3119: } -:3120: -:3121: @override function visitOptAccessExpression(OptAccessExpression* node) -:3122: { 165:3123: node.expression = expressionSemantic(node.expression, scope); 165:3124: node.type = node.expression.type; 330:3125: if var auto tc = toCondition(node.expression, scope) do 164:3126: node.expression = tc; 1:3127: else do return setError(node); 164:3128: if node.expression.operator != notEqual && node.expression.operator != leftParen do -:3129: { 1:3130: error(scope.filename, node.startPos, "optional access only works on symbol with members, not on `%s` of type `%s`", -:3131: format(node.expression).ptr, format(node.expression.type).ptr); 1:3132: return setError(node); -:3133: } 163:3134: } -:3135: -:3136: @override function visitOptAssignExpression(OptAssignExpression* node) -:3137: { 84:3138: processBinaryOperands(node); -:3139: -:3140: // `a.length ?= b` -> `setLength(a, b)` 84:3141: if tryToSetLengthExp(node) do -:3142: { -:3143: // `setLength(a, b)` -> `setLength(a, a.length ? b)` 2:3144: var auto se = asSetLengthExp(result); 2:3145: var auto vd = createVariable(node.startPos, Token.generateIdentifier(), TypeUSize(), scope, true); 2:3146: var auto ae = (new AssignExpression).create(node.startPos, varToIdentExp(vd), node.left); 2:3147: var auto cm = toCondition(node.left, scope); 2:3148: var auto ce = (new ConditionalExpression).create(node.startPos, cm, ae, se.newLength); 2:3149: se.newLength = expressionSemantic(ce, scope); 2:3150: result = se; 2:3151: return; -:3152: } -:3153: 82:3154: checkIfAssignable(node.left); 82:3155: tryOneWayAssImplicitConv(node); 164:3156: if var auto c = toCondition(node.left, scope) do 81:3157: node.condition = c; 82:3158: } -:3159: -:3160: @override function visitOrAssignExpression(const OrAssignExpression* node) -:3161: { 8:3162: visitBinaryAssignExpression(node); 8:3163: } -:3164: -:3165: @override function visitOrExpression(const OrExpression* node) -:3166: { 52:3167: visitBinaryExpression(node); 52:3168: } -:3169: -:3170: @override function visitOrOrExpression(const OrOrExpression* node) -:3171: { 394:3172: visitAndAndExpression(node); 394:3173: } -:3174: -:3175: @override function visitPostDecExpression(PostDecExpression* node) -:3176: { 519:3177: processUnaryOperand(node); 519:3178: const auto ne = node.expression; 519:3179: if tryRewritingToOperatorOverload(node, [ne]) do 2:3180: return; -:3181: 1034:3182: if var auto le = asLengthExp(ne) do -:3183: { 10:3184: checkIfAssignable(le.expression); 10:3185: var auto be = node.operator == TokenType.minMin ? new SubExpression else new AddExpression; 10:3186: be = be.create(node.startPos, le, (new IntegerExpression).create(le.startPos, null, 1, TypeUSize())); 10:3187: var auto sle = (new SetLengthExpression).create(le.expression, be, TypeUSize(), true); 10:3188: result = (new TupleExpression).create(node.startPos, [le:Expression*, sle:Expression*]); 10:3189: result = (new IndexExpression).create(node.startPos, result, (new IntegerExpression).create(node.startPos, null, 0, TypeUSize())); 10:3190: result = expressionSemantic(result , scope); 10:3191: return; -:3192: } -:3193: 507:3194: const auto isIntegral = ne.type.isIntegral(); 507:3195: const auto isFloating = ne.type.isFloating(); 507:3196: const auto isPtr = asTypePointer(ne.type) != null; 507:3197: if !isIntegral && !isFloating && !isPtr do -:3198: { 3:3199: error(scope.filename, node.startPos, "post `%s` not allowed on `%s` of type `%s`", -:3200: tokenString[node.operator].ptr, format(ne).ptr, format(ne.type).ptr); 3:3201: return setError(node); -:3202: } 504:3203: node.type = ne.type; 504:3204: checkIfAssignable(ne); 504:3205: } -:3206: -:3207: @override function visitPostIncExpression(const PostIncExpression* node) -:3208: { 447:3209: visitPostDecExpression(node); 447:3210: } -:3211: -:3212: @override function visitPreDecExpression(PreDecExpression* node) -:3213: { 252:3214: processUnaryOperand(node); 252:3215: const auto ne = node.expression; 252:3216: if tryRewritingToOperatorOverload(node, [ne]) do 2:3217: return; -:3218: 500:3219: if var auto le = asLengthExp(ne) do -:3220: { 3:3221: checkIfAssignable(le.expression); 3:3222: var auto be = node.operator == eopPreDec ? new SubExpression else new AddExpression; 3:3223: be = be.create(node.startPos, le, (new IntegerExpression).create(le.startPos, null, 1, TypeUSize())); 3:3224: var auto sle = (new SetLengthExpression).create(le.expression, be, TypeUSize(), true); 3:3225: result = sle; 3:3226: return; -:3227: } 247:3228: checkIfAssignable(ne); -:3229: 247:3230: node.type = ne.type; 247:3231: const auto isIntegral = ne.type.isIntegral(); 247:3232: const auto isFloating = ne.type.isFloating(); 247:3233: const auto isPtr = asTypePointer(ne.type) != null; 247:3234: if !isIntegral && !isFloating && !isPtr do 3:3235: return unaryNotSupportedOnTypeError(node); 244:3236: } -:3237: -:3238: @override function visitPreIncExpression(const PreIncExpression* node) -:3239: { 149:3240: visitPreDecExpression(node); 149:3241: } -:3242: -:3243: @override function visitRShiftAssignExpression(const RShiftAssignExpression* node) -:3244: { 3:3245: visitBinaryAssignExpression(node); 3:3246: } -:3247: -:3248: @override function visitRShiftExpression(const RShiftExpression* node) -:3249: { 9:3250: visitBinaryExpression(node); 9:3251: } -:3252: -:3253: @override function visitRangeExpression(RangeExpression* node) -:3254: { 914:3255: processBinaryOperands(node); 914:3256: if tryRewritingToOperatorOverload(node, [node.left, node.right]) do 1:3257: return; -:3258: 913:3259: session.startGagging(); 913:3260: var auto maybeLeft = implicitConvTo(node.left, node.right.type, scope); 913:3261: var auto maybeRight = implicitConvTo(node.right, node.left.type, scope); 913:3262: session.stopGagging(); -:3263: 913:3264: if !maybeRight && !maybeLeft do 7:3265: error(scope.filename, node.startPos, "cannot find the common type of the lower and upper bounds"); 913:3266: if maybeLeft do 903:3267: node.left = maybeLeft; 10:3268: else do if maybeRight do 3:3269: node.right = maybeRight; -:3270: 913:3271: var auto em1 = symToEnumMember(node.left.symbol); 913:3272: var auto lie = asIntegerExp(!em1 ? node.left else em1.value); 913:3273: var auto em2 = symToEnumMember(node.right.symbol); 913:3274: var auto rie = asIntegerExp(!em2 ? node.right else em2.value); 913:3275: if lie && rie && lie.value > rie.value do -:3276: { 4:3277: error(scope.filename, node.startPos, "invalid range, `%d` > `%d`", lie.value, rie.value); 4:3278: node.elemType = TypeError.instance(); 4:3279: return setError(node); -:3280: } -:3281: 1818:3282: if var auto re = asRangeExp(node.right) do -:3283: { 1:3284: error(scope.filename, node.startPos, "multi dimensional ranges have no applications"); 1:3285: node.elemType = TypeError.instance(); 1:3286: return setError(node); -:3287: } -:3288: 908:3289: node.type = TypeRange.instance(); 908:3290: node.elemType = node.left.type; 908:3291: } -:3292: -:3293: @override function visitRcaAssignExpression(RcaAssignExpression* node) -:3294: { 238:3295: if node.expression.type.kind != tkSlice do -:3296: { 124:3297: node.expression = (new SliceExpression).create(node.startPos, node.expression); 124:3298: node.expression = expressionSemantic(node.expression, scope); -:3299: } 238:3300: var auto tm = asTypeModified(node.expression.type); 238:3301: var auto ta = (new TypeRcArray).create(tm.modified); 238:3302: var auto vd = createVariable(node.startPos, Token.generateIdentifier(), ta, scope, true); 238:3303: var auto id = varToIdentExp(vd); 238:3304: node.ptr = (new PtrExpression).create(node.expression, (new TypePointer).create(tm.modified.resolved()), true); 238:3305: node.length = (new LengthExpression).create(node.expression, true, TypeUSize()); 238:3306: node.type = ta; 238:3307: node.target = id; 238:3308: } -:3309: -:3310: @override function visitSliceExpression(SliceExpression* node) -:3311: { 2091:3312: processUnaryOperand(node); -:3313: 2091:3314: var auto ta = asTypeStaticArray(node.expression.type); 2091:3315: var auto ts = asTypeSlice(node.expression.type); 2091:3316: var auto tra = asTypeRcArray(node.expression.type); 2091:3317: var auto tp = asTypePointer(node.expression.type); 2091:3318: node.isStatic= scope.func == null; -:3319: var bool isStaticallyBoundChecked; -:3320: 2091:3321: if node.isStatic && node.expression.asArrayExp() do -:3322: { 9:3323: node.staticPtrProvider = createVariable(node.startPos, Token.generateIdentifier(), node.expression.type, scope, false); 9:3324: node.staticPtrProvider.initializer = node.expression; -:3325: } -:3326: 2091:3327: if !node.range do -:3328: { 1544:3329: if tryRewritingToOperatorOverload(node, [node.expression]) do 1:3330: return; -:3331: -:3332: // Type[] | Type[+] -> TypeExp 3086:3333: if var auto te = asTypeExp(node.expression) do -:3334: { 31:3335: var auto t = node.tryAsTypeRca ? (new TypeRcArray).create(te.type) else (new TypeSlice).create(te.type); 31:3336: result = (new TypeExpression).create(node.startPos, resolveType(t, scope), true); 31:3337: return; -:3338: } -:3339: 1512:3340: isStaticallyBoundChecked = true; -:3341: 1512:3342: var Expression* left = (new IntegerExpression).create(node.startPos, null, 0, TypeUSize()); -:3343: var Expression* right; -:3344: -:3345: // array[] -> array[0 .. array.length] 1512:3346: if ts || tra do -:3347: { 341:3348: right = (new LengthExpression).create(node.expression, true, TypeUSize()); -:3349: } 1171:3350: else do if ta do -:3351: { 144:3352: right = ta.lengthExp; -:3353: } -:3354: // "string" -> "string"[0 .. ] 2054:3355: else do if var auto se = asStringExp(node.expression) do -:3356: { 1024:3357: right = (new IntegerExpression).create(node.startPos, null, se.value.text().length, TypeUSize()); -:3358: } -:3359: else do -:3360: { 3:3361: error(scope.filename, node.expression.startPos, "cannot automatically slice expression `%s` of type `%s`", -:3362: format(node.expression).ptr, format(node.expression.type).ptr); 3:3363: return setError(node); -:3364: } 1509:3365: node.range = (new RangeExpression).create(node.startPos, left, right); -:3366: } -:3367: else do -:3368: { 547:3369: scope = scope.pushDollar(node.expression); 547:3370: visitRangeExpression(node.range); 547:3371: scope = scope.pop(); -:3372: 547:3373: if tryRewritingToOperatorOverload(node, [node.expression, node.range.left, node.range.right]) do 2:3374: return; -:3375: -:3376: // Type[e1 .. e2] -> TypeElements 1090:3377: if var auto te = asTypeExp(node.expression) do -:3378: { 2:3379: var auto t = (new TypeElements).create(te.type, [node.range:Expression*]); 2:3380: result = (new TypeExpression).create(node.startPos, resolveType(t, scope), true); 2:3381: return; -:3382: } -:3383: 1086:3384: if var auto e = implicitConvTo(node.range.left, TypeUSize(), scope) do 541:3385: node.range.left = e; 1086:3386: if var auto e = implicitConvTo(node.range.right, TypeUSize(), scope) do 540:3387: node.range.right = e; -:3388: 543:3389: var auto leftI = getIntLiteral(node.range.left); 543:3390: var auto rightI = getIntLiteral(node.range.right); 543:3391: var auto tsa = asTypeStaticArray(node.expression.type); 543:3392: var auto ie = tsa ? getIntLiteral(tsa.lengthExp) else null; 543:3393: if ie && leftI && rightI do -:3394: { 6:3395: isStaticallyBoundChecked = true; 6:3396: if leftI.value >= ie.value do 2:3397: error(scope.filename, node.startPos, "left index `%d` >= array length `%d`", leftI.value, ie.value); 6:3398: if rightI.value > ie.value do 1:3399: error(scope.filename, node.startPos, "right index `%d` > array length `%d`", rightI.value, ie.value); -:3400: } 543:3401: if node.isStatic do -:3402: { -:3403: var Expression* ev; 4:3404: if (ev = evaluate(node.range.left)) && ev.getIntLiteral() do 3:3405: node.range.left = ev; -:3406: else do 1:3407: error(scope.filename, node.startPos, "left index `%s` does not give an integer known at compile time", format(node.range.left).ptr); 4:3408: if (ev = evaluate(node.range.right)) && ev.getIntLiteral() do 3:3409: node.range.right = ev; -:3410: else do 1:3411: error(scope.filename, node.startPos, "right index `%s` does not give an integer known at compile time", format(node.range.right).ptr); -:3412: } -:3413: } -:3414: 2052:3415: if !isStaticallyBoundChecked do -:3416: { 537:3417: if ta do 14:3418: node.sourceLength = ta.lengthExp; 523:3419: else do if ts || tra do 171:3420: node.sourceLength = (new LengthExpression).create(node.expression, true, TypeUSize()); -:3421: } -:3422: 2052:3423: var auto slicedType = asTypeModified(node.expression.type); 2052:3424: if !slicedType do -:3425: { 1:3426: error(scope.filename, node.startPos, "cannot slice from type `%s` because it is not an array", format(node.expression.type).ptr); 1:3427: return setError(node); -:3428: } 2051:3429: if !node.range.left.type.isIntegral() && !isTypeBool(node.range.left.type) do -:3430: { 2:3431: error(scope.filename, node.range.left.startPos, "slice lower bound must be of an integer type and not `%s`", format(node.range.left.type).ptr); 2:3432: return setError(node); -:3433: } 2049:3434: if !node.range.right.type.isIntegral() && !isTypeBool(node.range.right.type) do -:3435: { 1:3436: error(scope.filename, node.range.right.startPos, "slice upper bound must be of an integer type and not `%s`", format(node.range.right.type).ptr); 1:3437: return setError(node); -:3438: } 2048:3439: if !node.isStatic && !tp && !node.expression.isLvalue() do -:3440: { 1:3441: error(scope.filename, node.expression.startPos, "cannot slice expression `%s` because it is not a lvalue", -:3442: format(node.expression).ptr); 1:3443: return setError(node); -:3444: } -:3445: 2047:3446: node.type = (new TypeSlice).create(slicedType.modified); -:3447: 2047:3448: if !node.isStatic do -:3449: { 1647:3450: var auto vd = createVariable(node.startPos, Token.generateIdentifier(), node.type, scope, false); 1647:3451: node.result = varToIdentExp(vd); 1647:3452: if ts || ta || tra do 662:3453: node.sourcePtr = (new PtrExpression).create(node.expression, (new TypePointer).create(slicedType.modified.resolved()), true); -:3454: } 2047:3455: } -:3456: -:3457: @override function visitStatement(const Statement* node) -:3458: { -:3459: assert(0); -:3460: } -:3461: -:3462: @override function visitStringExpression(StringExpression* node) -:3463: { 2924:3464: node.type = (new TypePointer).create(TypeS8.instance()); 2924:3465: } -:3466: -:3467: @override function visitSubAssignExpression(const SubAssignExpression* node) -:3468: { 134:3469: visitBinaryAssignExpression(node); 134:3470: } -:3471: -:3472: @override function visitSuperExpression(SuperExpression* node) -:3473: { 109:3474: var auto fd = scope.func; 109:3475: if !fd || !fd.parameters.length || fd.parameters[0].name != thisToken() do -:3476: { 2:3477: error(scope.filename, node.startPos, "`super` cannot be used without `this` context"); 2:3478: return setError(node); -:3479: } 107:3480: var auto tp = asTypePointer(fd.parameters[0].type); 107:3481: var auto tc = tp ? asTypeClass(tp.modified) else null; 107:3482: if !tc do -:3483: { 1:3484: error(scope.filename, node.startPos, "`super` can only be used in class member functions"); 1:3485: return setError(node); -:3486: } 106:3487: if tc.declaration.inheritanceList.length == 0 do -:3488: { 1:3489: error(scope.filename, node.startPos, "`super` can only be used in derived classes"); 1:3490: return setError(node); -:3491: } -:3492: // allow to find exact match in the parent vtbl 105:3493: var auto tcPrev = tc.declaration.inheritanceList[0]; 105:3494: scope.setSym(tcPrev.asSymbol()); 105:3495: node.type = (new TypePointer).create(tcPrev); 105:3496: } -:3497: -:3498: @override function visitSubExpression(const SubExpression* node) -:3499: { 520:3500: visitBinaryExpression(node); 520:3501: } -:3502: -:3503: @override function visitThisExpression(const ThisExpression* node) -:3504: { 730:3505: visitIdentExpression(node:IdentExpression*); 730:3506: } -:3507: -:3508: @override function visitTupleExpression(TupleExpression* node) -:3509: { 167:3510: node.allCanInitialize = true; 167:3511: node.allLvalues = true; 167:3512: var auto allTypeExps = true; -:3513: var Type*[+] types; -:3514: 167:3515: foreach var auto e in node.expressions do -:3516: { 366:3517: var auto te = asTypeExp(e); 395:3518: if te do te.raw = false; 366:3519: e = expressionSemantic(e, scope.pushNested()); 395:3520: if te do te.raw = true; 366:3521: allTypeExps &= te != null; -:3522: } -:3523: -:3524: // (TypeExp, TypeExp) -> TypeExp(TypeTuple) 167:3525: if allTypeExps do -:3526: { 11:3527: types.length = node.expressions.length; 11:3528: foreach (const auto i; var auto e) in node.expressions do 26:3529: types[i] = e.type.resolved(); 11:3530: var auto tt = (new TypeTuple).create(types); 11:3531: var auto t = resolveType(tt, scope); 11:3532: result = (new TypeExpression).create(node.startPos, t, true, true); 11:3533: return; -:3534: } -:3535: 156:3536: expandTuples(node.expressions, 0); 156:3537: types.length = node.expressions.length; 156:3538: foreach (const auto i; const auto e) in node.expressions do -:3539: { 343:3540: assert(e.type, format(e).ptr); 343:3541: var auto t = e.type.resolved(); 343:3542: if !t.isVariableType() do // that includes TypeError 5:3543: error(scope.filename, e.startPos, "tuple element `%s` cannot be of type `%s`", format(e).ptr, format(t).ptr); 343:3544: types[i] = t; 343:3545: node.allCanInitialize &= e.canInitialize(); 343:3546: var auto te = asTupleExp(e); 343:3547: node.allLvalues &= te ? te.allLvalues else e.isLvalue(); -:3548: } 156:3549: var auto tt = (new TypeTuple).create(types); 156:3550: memulateTypeTuple(tt, scope); 156:3551: node.type = tt; -:3552: 156:3553: if scope.func && !node.allCanInitialize do 80:3554: node.value = createVariable(node.startPos, Token.generateIdentifier(), node.type, scope, false); 156:3555: node.type.progress = done; 156:3556: } -:3557: -:3558: @override function visitTypeExpression(TypeExpression* node) -:3559: { 629:3560: if node.type do -:3561: { 55:3562: result = node; 55:3563: return; -:3564: } 574:3565: scope = scope.pushNested(); 574:3566: node.type = resolveType(node.wrapped, scope); 574:3567: scope = scope.pop(); 574:3568: if node.raw do -:3569: { 6:3570: error(scope.filename, node.startPos, "expressions wrapping a type can only be dotted"); 6:3571: return setError(node); -:3572: } -:3573: // to solve properties on basic types; 1136:3574: if var auto ts = node.type.asSymbol() do 36:3575: scope.setSym(ts); -:3576: // see .sizeof 568:3577: result = node; 568:3578: } -:3579: -:3580: @override function visitXorAssignExpression(const XorAssignExpression* node) -:3581: { 6:3582: visitBinaryAssignExpression(node); 6:3583: } -:3584: -:3585: @override function visitXorExpression(const XorExpression* node) -:3586: { 4:3587: visitBinaryExpression(node); 4:3588: } -:3589:} -:3590: -:3591:/// Cast an array literal to another array type using the other array elements types. -:3592:function castArrayLiteralElements(ArrayExpression* ae; TypeStaticArray* other; Scope* scope): ArrayExpression* -:3593:{ 46:3594: var auto t = other.modified; 46:3595: foreach var auto e in ae.items do -:3596: { 1316:3597: e = (new CastExpression).create(e.startPos, e, t); 1316:3598: e = expressionSemantic(e, scope); -:3599: } 46:3600: ae.type = other; 46:3601: if ae.asLvalue do 17:3602: asVariableDeclaration(ae.asLvalue).type = other; 46:3603: return ae; -:3604:} -:3605: -:3606:/// Cast an array literal to a set of enum members -:3607:function castArrayLiteralToEnumSet(ArrayExpression* al; TypeEnumSet* tes; Scope* scope): Expression* -:3608:{ -:3609: var u64 set; 42:3610: foreach var auto e in al.items do -:3611: { 91:3612: var auto em = symToEnumMember(e.symbol); 91:3613: if !em do 1:3614: return null; 90:3615: var auto ie = getIntLiteral(em.value); 90:3616: set |= 1 << ie.value; -:3617: } 41:3618: return (new IntegerExpression).create(al.startPos, null, set, tes); -:3619:} -:3620: -:3621:/** Cast a static array made of enum members to a EnumSet in the form of -:3622: * an integer expression if the elements are known and as a DeclExp, e.g -:3623: * `[E.e1, E.e2]` -> `var ESet eset; eset += E.e1; eset += E.e2;`, otherwise. -:3624: */ -:3625:function castStaticArrayToEnumSet(Expression* staExp; TypeEnumSet* tes; Scope* scope): Expression* -:3626:{ 42:3627: var auto ae = asArrayExp(staExp); 42:3628: var auto de = asDeclExp(staExp); 42:3629: if !ae && de do -:3630: { -:3631: // An ArrayExp can be hidden by a temporary created to turn it as an lvalue. 54:3632: if var auto da = de.expression do 54:3633: if var auto as = asAssignExp(da) do 27:3634: ae = asArrayExp(as.right); -:3635: } 126:3636: if ae do if var auto e = castArrayLiteralToEnumSet(ae, tes, scope) do 41:3637: return e; -:3638: 1:3639: var auto tsa = asTypeStaticArray(staExp.type); 1:3640: var auto ptrBase = (new PtrExpression).create(staExp, (new TypePointer).create(tsa.modified.resolved()), false); 1:3641: var auto vd = createVariable(staExp.startPos, Token.generateIdentifier(), tes, scope, true); 1:3642: var auto id = varToIdentExp(vd); 1:3643: var auto exps = (new Expression*[+])(tsa.length()); 1:3644: foreach (const auto i; var auto e) in exps do -:3645: { 1:3646: var auto index = (new IntegerExpression).create(staExp.startPos, null, i, TypeS32.instance()); 1:3647: var auto ie = (new IndexExpression).create(staExp.startPos, staExp, index, tes.modified); 1:3648: ie.arrayType = tsa; 1:3649: ie.expression = ptrBase; -:3650: // so that bounds are not checked 1:3651: ie.sourceLength= null; 1:3652: e = (new AddAssignExpression).create(staExp.startPos, id, ie, tes); -:3653: } 1:3654: var auto me = (new TupleExpression).create(staExp.startPos, exps):Expression*; 1:3655: me = (new IndexExpression).create(staExp.startPos, me, (new IntegerExpression).create(staExp.startPos, null, exps.length - 1, TypeUSize())); 1:3656: me = expressionSemantic(me , scope); 1:3657: return (new DeclExpression).create(staExp.startPos, vd, me, tes, vd.symbol); -:3658:} -:3659: -:3660:function commonClassPointerType(Type*[] types): Type* -:3661:{ 84:3662: if types.length < 2 do 26:3663: return null; -:3664: 58:3665: while true do -:3666: { -:3667: label L0; -:3668: 130:3669: if types.length == 1 do 53:3670: return types.ptr[0]; -:3671: 77:3672: var auto t0 = types.ptr[0].resolved(); 77:3673: var auto t1 = types[$-1].resolved(); 77:3674: const auto isNull0 = isTypeNull(t0); 77:3675: const auto isNull1 = isTypeNull(t1); -:3676: -:3677: // [null, A*, B*, ... , A*, null] 77:3678: if isNull0 && isNull1 do -:3679: { 1:3680: assert(types.length > 2); 1:3681: types = types[1 .. $-1]; 1:3682: continue; -:3683: } -:3684: 76:3685: var auto tp0 = asTypePointer(t0); 76:3686: var auto tp1 = asTypePointer(t1); 76:3687: var auto tc0 = tp0 ? asTypeClass(tp0.modified) else null; 76:3688: var auto tc1 = tp1 ? asTypeClass(tp1.modified) else null; -:3689: 76:3690: if !tc0 && !tc1 do 3:3691: return null; -:3692: -:3693: // [null, A*, B*, ... , A*] 73:3694: if !tc0 && tc1 && isTypeNull(t0) do 1:3695: continue types = types[1 .. $]; -:3696: // [A*, B*, ... , A*, null] 72:3697: if tc0 && !tc1 && isTypeNull(t1) do 2:3698: continue types = types[0 .. $-1]; -:3699: // [A*, B*, ..., A*] 70:3700: if tc0 == tc1 do 31:3701: continue types = types[0 .. $-1]; 39:3702: if !tc0 || !tc1 do 1:3703: return null; -:3704: -:3705: var Type*[+] c0; -:3706: var Type*[+] c1; 38:3707: getInheritanceChain(tc0, c0); 38:3708: getInheritanceChain(tc1, c1); 38:3709: c0 ~= tc0; 38:3710: c1 ~= tc1; 38:3711: foreach var auto ti0 in c0.reverse do -:3712: { 75:3713: var auto ti0r = ti0.resolved(); 75:3714: foreach var auto ti1 in c1.reverse do 246:3715: if ti0r == ti1.resolved() do -:3716: { 37:3717: if tc0 != ti0r do 31:3718: types[0] = (new TypePointer).create(ti0r); 37:3719: continue @L0, types = types[0 .. $-1]; -:3720: } -:3721: } 1:3722: return null; -:3723: } -:3724:} -:3725: -:3726:/// Returns: If exp is an empty array literal the IdentExp for an empty slice, `null` otherwise -:3727:function emptyArrayToSlice(Expression* exp; Type* tm; Scope* sc): Expression* -:3728:{ 1134:3729: if exp.type:u8* != TypeEmptyArray.instance():u8* do 1118:3730: return null; -:3731: 16:3732: var auto t = asTypeModified(tm).modified.resolved(); 16:3733: var auto tsl = (new TypeSlice).create(t); 16:3734: var auto vd = createVariable(exp.startPos, Token.generateIdentifier(), tsl, sc, false); 16:3735: var auto id = varToIdentExp(vd); 16:3736: return (new DeclExpression).create(exp.startPos, vd, id, tsl, vd.symbol); -:3737:} -:3738: -:3739:/// Does CastKind.tupToElem -:3740:function tupleToElement(Expression* exp; Type* t; Scope* sc): Expression* -:3741:{ 3:3742: var auto tt = asTypeTuple(exp.type); 3:3743: var auto te = tt.types[0]; 3:3744: var auto id = (new IntegerExpression).create(exp.startPos, null, 0, TypeUSize()); 3:3745: var auto r = (new IndexExpression).create(exp.startPos, exp, id); 3:3746: while (tt = asTypeTuple(te)):u8* do -:3747: { 2:3748: r = (new IndexExpression).create(r.startPos, r, id); 2:3749: te = tt.types[0]; -:3750: } 3:3751: return expressionSemantic(r, sc); -:3752:} -:3753: -:3754:/// Does CastKind.elemToTup -:3755:function elementToTuple(Expression* exp; Type* t; Scope* sc): Expression* -:3756:{ 3:3757: var auto tt = asTypeTuple(t); 3:3758: var auto te = (new TupleExpression).create(exp.startPos, [exp]); 3:3759: while true do -:3760: { 6:3761: tt = asTypeTuple(tt.types[0]); 6:3762: if !tt do 3:3763: return expressionSemantic(te, sc); 3:3764: te = (new TupleExpression).create(exp.startPos, [te:Expression*]); -:3765: } -:3766:} -:3767: -:3768:/// Does CastKind.tupToStruct -:3769:function tupleToStruct(Expression* e; Type* t; Scope* sc): Expression* -:3770:{ 25:3771: var auto ts = asTypeStruct(t); 25:3772: var auto t0 = asTypeTuple(e.type); 25:3773: var auto t1 = ts.toTypeTuple(); 25:3774: if ts && t0 == t1 do -:3775: { 24:3776: foreach var auto d in ts.declaration.body.items do -:3777: { 140:3778: var auto vd = asVariableDeclaration(d); 140:3779: if vd && !vd.isStatic() && vd.isConst() do 1:3780: session.error(sc.filename, e.startPos, "cannot convert `%s` to a `%s` because its member `%s` is `const`", -:3781: format(e).ptr, format(ts).ptr, vd.name.text().ptr); -:3782: } 24:3783: if sc.func && e.isLvalue() do -:3784: { 10:3785: return forceCast(e, ts).expressionSemantic(sc); -:3786: } -:3787: else do -:3788: { 14:3789: e.type = ts; 14:3790: return e; -:3791: } -:3792: } 1:3793: return null; -:3794:} -:3795: -:3796:/** -:3797: * Try to replace echo expression with another expression. -:3798: */ -:3799:function evaluateEcho(EchoExpression* node; Scope* scope): Expression* -:3800:{ -:3801: function checkParameterCount(usize expected): bool -:3802: { 300:3803: if node.arguments.length != expected do -:3804: { 19:3805: session.error(scope.filename, node.startPos, "%d parameters expected for `%s`, and not %d", -:3806: expected, node.command.text().ptr, node.arguments.length); 19:3807: return false; -:3808: } 281:3809: return true; -:3810: } -:3811: -:3812: function getSymFromFirstArg(): Symbol* -:3813: { 24:3814: var auto a0 = node.arguments.ptr[0]; 24:3815: var auto t0 = a0.type.resolved(); 24:3816: var auto s0 = a0.symbol; 24:3817: s0 ?= t0.asSymbol(); 24:3818: return s0; -:3819: } -:3820: -:3821: function trueExp(): Expression* -:3822: { 104:3823: return (new BoolExpression).create(node.startPos, null, true, TypeBool.instance()); -:3824: } -:3825: -:3826: function falseExp(): Expression* -:3827: { 75:3828: return (new BoolExpression).create(node.startPos, null, false, TypeBool.instance()); -:3829: } -:3830: -:3831: function integerExp(u64 value): Expression* -:3832: { 1:3833: return (new IntegerExpression).create(node.startPos, null, value); -:3834: } -:3835: -:3836: function stringExp(Token* value): Expression* -:3837: { 8:3838: return (new StringExpression).create(node.startPos, value); -:3839: } -:3840: -:3841: function isXXXX(const SymbolKind sk): Expression* -:3842: { 17:3843: if !checkParameterCount(1) do 1:3844: return null; 16:3845: var auto s = getSymFromFirstArg(); 16:3846: return s && s.kind == sk ? trueExp() else falseExp(); -:3847: } -:3848: -:3849: function isSTC(const StorageClass stc): Expression* -:3850: { 6:3851: if !checkParameterCount(1) do 1:3852: return null; 5:3853: var auto s = getSymFromFirstArg(); 5:3854: var auto vd = symToVarDecl(s); 5:3855: return vd && stc in vd.stc ? trueExp() else falseExp(); -:3856: } -:3857: 301:3858: var auto args = node.arguments.ptr; 903:3859: switch node.command.text() do -:3860: { -:3861: on "version" do -:3862: { 2:3863: return checkParameterCount(0) ? stringExp(versionToken()) else null; -:3864: } -:3865: on "line" do -:3866: { 2:3867: return checkParameterCount(0) ? integerExp(node.startPos.line) else null; -:3868: } -:3869: on "filename" do -:3870: { 8:3871: return checkParameterCount(0) ? stringExp(identifier(scope.filename)) else null; -:3872: } -:3873: on "convert" do -:3874: { 16:3875: if !checkParameterCount(2) do 1:3876: return null; -:3877: var Type* tn; 15:3878: if args[1].operator == eopType do -:3879: { 14:3880: tn = asTypeExp(args[1]).type; -:3881: } 15:3882: if !tn do -:3883: { 1:3884: session.error(scope.filename, node.startPos, "expected type for the second `convert` parameter"); 1:3885: return null; -:3886: } 14:3887: session.startGagging(); 14:3888: var auto e = implicitConvTo(args[0], tn, scope); 14:3889: session.stopGagging(); 14:3890: return e ? trueExp() else falseExp(); -:3891: } 2:3892: on "isConst" do return isSTC(StorageClass.$const); 1:3893: on "isStatic" do return isSTC(StorageClass.$static); 3:3894: on "isVar" do return isSTC(StorageClass.$var); 3:3895: on "isClass" do return isXXXX(SymbolKind.$class); 2:3896: on "isStruct" do return isXXXX(SymbolKind.$class); 2:3897: on "isUnion" do return isXXXX(SymbolKind.$union); 10:3898: on "isFunction" do return isXXXX(SymbolKind.$function); -:3899: on "isTuple" do -:3900: { 4:3901: if !checkParameterCount(1) do 1:3902: return null; 3:3903: return asTypeTuple(args[0].type) ? trueExp() else falseExp(); -:3904: } -:3905: on "isPointer" do -:3906: { 7:3907: if !checkParameterCount(1) do 1:3908: return null; 6:3909: return asTypePointer(args[0].type) ? trueExp() else falseExp(); -:3910: } -:3911: on "isUnit" do -:3912: { 4:3913: if !checkParameterCount(1) do 1:3914: return null; 3:3915: var auto s = getSymFromFirstArg(); 3:3916: return s?.kind in unitKinds ? trueExp() else falseExp(); -:3917: } -:3918: on "getPointedType" do -:3919: { 3:3920: if !checkParameterCount(1) do 1:3921: return null; 4:3922: if var TypePointer* tp = asTypePointer(args[0].type) do 1:3923: return (new TypeExpression).create(node.startPos, tp.modified.resolved(), true); 1:3924: session.error(scope.filename, node.startPos, "the first `getPointedType` parameter must represent a pointer"); 1:3925: return null; -:3926: } -:3927: on "is" do -:3928: { 130:3929: if !checkParameterCount(2) do 2:3930: return null; -:3931: -:3932: var Symbol* s0; -:3933: var Symbol* s1; -:3934: var Type* t0; -:3935: var Type* t1; -:3936: 128:3937: t0 = args[0].type.resolved(); 128:3938: s0 = args[0].symbol; 128:3939: assert(!s0 || s0.kind != SymbolKind.$alias); 128:3940: t1 = args[1].type.resolved(); 128:3941: s1 = args[1].symbol; 128:3942: assert(!s1 || s1.kind != SymbolKind.$alias); -:3943: 128:3944: if s0 && s1 do 29:3945: return s0 == s1 ? trueExp() else falseExp(); 99:3946: else do if t0 && t1 do 99:3947: return t0 == t1 ? trueExp() else falseExp(); -:3948: assert(0, "add this case to the test suite"); -:3949: } -:3950: on "getUnittests" do -:3951: { 15:3952: if !checkParameterCount(1) do 1:3953: return null; 14:3954: if !args[0].symbol || args[0].symbol.kind !in unitKinds do -:3955: { 2:3956: session.error(scope.filename, node.startPos, "the first `getUnittests` parameter must represent a unit"); 2:3957: return null; -:3958: } -:3959: // `[&test1, &test2, ...]` 12:3960: var auto array = (new ArrayExpression).create(node.startPos); 12:3961: foreach var auto s in args[0].symbol.children do -:3962: { 67:3963: var auto fd = symToFuncDecl(s); 67:3964: if !fd || !fd.getAtUnittest() do 52:3965: continue; -:3966: // the ident here can represent an arbitrary long chain, so just use one and pretend that -:3967: // the sema is already run 15:3968: var auto id = (new IdentExpression).create(node.startPos, fd.name, fd.asTypeDeclared, fd.symbol); 15:3969: array.items ~= (new AtExpression).create(node.startPos, id, (new TypePointer).create(TypeFunction.unittestType())); -:3970: } 12:3971: if array.items.length == 0 do -:3972: { -:3973: // need valid array literal type even if empty 3:3974: var auto ie = (new IntegerExpression).create(array.startPos, null, 0, TypeUSize()); 3:3975: array.type = (new TypeStaticArray).create((new TypePointer).create(TypeFunction.unittestType()), ie); 3:3976: array.type.progress = SemanticProgress.done; -:3977: } 12:3978: return array; -:3979: } -:3980: on "func_t" do -:3981: { 41:3982: if !checkParameterCount(0) do 1:3983: return null; 40:3984: if !scope.func do -:3985: { 1:3986: session.error(scope.filename, node.startPos, "`echo(func_t)` is only supported in function bodies"); 1:3987: return null; -:3988: } 39:3989: return (new TypeExpression).create(node.startPos, scope.func.asTypeDeclared, true); -:3990: } -:3991: on "func" do -:3992: { 18:3993: if !checkParameterCount(0) do 1:3994: return null; 17:3995: if !scope.func do -:3996: { 1:3997: session.error(scope.filename, node.startPos, "`echo(func)` is only supported in function bodies"); 1:3998: return null; -:3999: } 16:4000: var auto fd = scope.func; 16:4001: return (new IdentExpression).create(node.startPos, fd.name, fd.asTypeDeclared, fd.symbol); -:4002: } -:4003: on "getLastTemporary" do -:4004: { 3:4005: if !checkParameterCount(0) do 1:4006: return null; 2:4007: if scope.func do -:4008: { 2:4009: var auto fd = scope.func; 2:4010: foreach const auto vd in fd.allocas.reverse do 1:4011: if isTemp in vd.flags do 1:4012: return varToIdentExp(vd); -:4013: } 1:4014: session.error(scope.filename, node.startPos, "no temporaries available at this point"); 1:4015: return null; -:4016: } -:4017: on "type" do -:4018: { 15:4019: if !checkParameterCount(1) do 1:4020: return null; 14:4021: return (new TypeExpression).create(node.startPos, args[0].type.resolved(), true); -:4022: } -:4023: on "return" do -:4024: { 4:4025: if !checkParameterCount(1) do 1:4026: return null; 3:4027: var auto fd = symToFuncDecl(args[0].symbol); 3:4028: if !fd do -:4029: { 2:4030: session.error(scope.filename, node.startPos, "the first echo argument does not give a function"); 2:4031: return null; -:4032: } 1:4033: return (new TypeExpression).create(node.startPos, fd.returnType.resolved(), true); -:4034: } -:4035: on "isArray" do -:4036: { 5:4037: if !checkParameterCount(1) do 1:4038: return null; 4:4039: const auto k = args[0].type.kind; 4:4040: return k == tkSta || k == tkRca || k == tkSlice ? trueExp() else falseExp(); -:4041: } -:4042: else do -:4043: { 1:4044: session.error(scope.filename, node.startPos, "invalid echo command `%s`", node.command.text().ptr); 1:4045: return null; -:4046: } -:4047: } -:4048:} -:4049: -:4050:/** Force a cast using pointer + deref -:4051: * -:4052: * Params: -:4053: * e = expression to cast -:4054: * targetType = type of result -:4055: * -:4056: * Returns: `*((&e):targetType*)` */ -:4057:function forceCast(Expression* e; Type* targetType): Expression* -:4058:{ 16:4059: var auto a = (new AtExpression).create(e.startPos, e, (new TypePointer).create(e.type)); 16:4060: var auto p = (new CastExpression).create(e.startPos, a, (new TypePointer).create(targetType), CastKind.bitCast, true); 16:4061: return (new DerefExpression).create(e.startPos, p, targetType); -:4062:} -:4063: -:4064:/** Determine the kind of cast when trying to convert an expression to another type. -:4065: * This function is common to `CastExpression` semantics and `implicitConvTo()`. -:4066: * -:4067: * Params: -:4068: * e = the expression to convert -:4069: * toType = the new type -:4070: */ -:4071:function getCastKind(Expression* e; Type* toType): CastKind -:4072:{ 90549:4073: var auto t1 = e.type.resolved(); 90549:4074: var auto t2 = toType.resolved(); 90549:4075: assert (t1 && t2); 90549:4076: if t1:u8* == t2:u8* || t1 == t2 do 72376:4077: return CastKind.same; -:4078: 18173:4079: const auto isExt = t1.size < t2.size; 18173:4080: const auto isTrunc = t1.size > t2.size; 18173:4081: const auto isSameSize = t1.size == t2.size; -:4082: 18173:4083: var auto se = asStringExp(e); 18173:4084: var auto ae = asArrayExp(e); 18173:4085: var auto de = asDeclExp(e); 18173:4086: if !ae && de do -:4087: { -:4088: // An ArrayExp can be hidden by a temporary created to turn it as an lvalue. 304:4089: if var auto da = de.expression do 304:4090: if var auto as = asAssignExp(da) do 133:4091: ae = asArrayExp(as.right); -:4092: } -:4093: 18173:4094: const auto isFromInt = t1.isIntegral() || isTypeBool(t1); 18173:4095: const auto isFromFp = t1.isFloating(); -:4096: 18173:4097: const auto isToInt = t2.isIntegral() || isTypeBool(t2); 18173:4098: const auto isToFp = t2.isFloating(); -:4099: 18173:4100: var auto tsl1 = asTypeSlice(t1); 18173:4101: var auto tsl2 = asTypeSlice(t2); -:4102: 18173:4103: var auto tra1 = asTypeRcArray(t1); 18173:4104: var auto tra2 = asTypeRcArray(t2); -:4105: 18173:4106: var auto tsa1 = asTypeStaticArray(t1); 18173:4107: var auto tsa2 = asTypeStaticArray(t2); -:4108: 18173:4109: var auto tp1 = asTypePointer(t1); 18173:4110: var auto tp2 = asTypePointer(t2); -:4111: 18173:4112: var auto tcp1 = tp1 ? asTypeClass(tp1.modified) else null; 18173:4113: var auto tcp2 = tp2 ? asTypeClass(tp2.modified) else null; -:4114: 18173:4115: var auto tcs1 = asTypeClass(t1); 18173:4116: var auto tcs2 = asTypeClass(t2); -:4117: 18173:4118: var auto tes1 = asTypeEnumSet(t1); 18173:4119: var auto tes2 = asTypeEnumSet(t2); 18173:4120: var auto te2 = tes2 ? asTypeEnum(tes2.declaration.asTypeDeclared) else asTypeEnum(t2); -:4121: 18173:4122: var auto tt1 = asTypeTuple(t1); 18173:4123: var auto tt2 = asTypeTuple(t2); -:4124: 18173:4125: const auto isToBool = isTypeBool(t2); -:4126: 18173:4127: if isToBool && (isFromInt || isFromFp || tsl1 || tra1 || tsa1 || tp1 || tes1) do 18:4128: return CastKind.toCond; -:4129: 18155:4130: if isTypeVoid(toType) do 8:4131: return CastKind.voidCast; -:4132: -:4133: // class casts, static is always allowed, dynamic must be explicit 18147:4134: if tcs1 && tcs2 && e.isLvalue() do 5:4135: return inheritsOf(tcs1, tcs2) ? CastKind.staticCastS else CastKind.dynCastS; 18142:4136: if tcp1 && tcp2 do -:4137: { -:4138: // re-use of parent ctor 4960:4139: if var auto ce = asCallExp(e) do -:4140: { 578:4141: var auto fd = getFuncDeclForCall(ce); 578:4142: if FunctionFlag.isCtor in fd?.flags && inheritsOf(tcp2, tcp1) do 9:4143: return CastKind.staticCastP; -:4144: } 2471:4145: return inheritsOf(tcp1, tcp2) ? CastKind.staticCastP else CastKind.dynCastP; -:4146: } -:4147: -:4148: // always allowed, i.e implicitly 15662:4149: if isFromInt && isToInt && isExt do 4728:4150: return CastKind.intExt; 10934:4151: if isFromInt && isToInt && isSameSize do 3104:4152: return CastKind.same; 7830:4153: if isExt && isFromFp && isToFp do 13:4154: return CastKind.fpExt; 7817:4155: if isFromInt && isToFp do 34:4156: return CastKind.intToFp; 7783:4157: if isTypeNull(t1) && tp2 do 1132:4158: return CastKind.nullCast; 6651:4159: if tp1 && tp2 do -:4160: { 1368:4161: var auto t = asTypeStaticArray(tp1.modified); 1368:4162: while t do -:4163: { 7:4164: if t.modified.resolved() == tp2.modified.resolved() do 5:4165: return CastKind.staToPtr; 2:4166: t = asTypeStaticArray(t.modified); -:4167: } -:4168: } 6646:4169: if isFromInt && tes2 do 127:4170: return CastKind.intToSet; 6519:4171: if isFromInt && te2 do -:4172: { 16:4173: if var auto ie1 = getIntLiteral(e) do -:4174: { 8:4175: const auto members = te2.declaration.members[]; 8:4176: foreach var auto m in members do -:4177: { 28:4178: if var auto ie = getIntLiteral(m.value) do 14:4179: if ie.value == ie1.value do 6:4180: return CastKind.intToEnum; -:4181: } -:4182: } 2:4183: return CastKind.invalid; -:4184: } 6511:4185: if ae && tsa1 && tsa2 && tsa1.length() == tsa2.length() do -:4186: { 50:4187: const auto elemCk = getCastKind(ae.items.ptr[0], tsa2.modified); 50:4188: return elemCk != CastKind.invalid ? CastKind.staElems else elemCk; -:4189: } 6461:4190: if se && isToInt do 877:4191: return se.value.text().length == 1 ? CastKind.strToChar else CastKind.invalid; -:4192: 5584:4193: if se && tsl2 && isTypeS8(tsl2.modified.resolved()) do 776:4194: return CastKind.strToDyna; 4808:4195: if tsa1 && tsl2 && tsa1.modified.resolved() == tsl2.modified.resolved() do 67:4196: return CastKind.staToDyna; 4741:4197: if tsa1 && tes2 && tsa1.modified.resolved() == tes2.declaration.asTypeDeclared do 35:4198: return CastKind.staToESet; -:4199: 4706:4200: if se && tra2 && isTypeS8(tra2.modified.resolved()) do 101:4201: return CastKind.strToRca; 4605:4202: if tsa1 && tra2 && tsa1.modified.resolved() == tra2.modified.resolved() do 23:4203: return CastKind.staToRca; 4582:4204: if tra1 && tsl2 && tra1.modified.resolved() == tsl2.modified.resolved() do 63:4205: return CastKind.rcaToDyna; 4519:4206: if tsl1 && tra2 && tsl1.modified.resolved() == tra2.modified.resolved() do 109:4207: return CastKind.dynaToRca; -:4208: 4410:4209: if se && tsa2 && isTypeS8(tsa2.modified) && se.value.text().length == tsa2.length() do 2:4210: return CastKind.strToSta; 4408:4211: if isToBool && asTypeAggregate(t1) do 5:4212: return CastKind.opTrue; -:4213: 4403:4214: if ae && !ae.items.length && tra2 do 5:4215: return CastKind.staToRca; 4398:4216: if ae && !ae.items.length && tsl2 do 11:4217: return CastKind.staToDyna; -:4218: 4387:4219: if tp1 && tp2 do -:4220: { -:4221: // allow lambda passed as parameter to return derived class ptr 1363:4222: var auto tf1 = asTypeFunction(tp1.modified); 1363:4223: var auto tf2 = asTypeFunction(tp2.modified); 1363:4224: if tf1 && tf2 && tf1.isCovariantWith(tf2) do 2:4225: return CastKind.funRet; -:4226: } -:4227: 4385:4228: if tt1 && tt1.isSingleElement() == t2 do 3:4229: return CastKind.tupToElem; 4382:4230: if tt2 && tt2.isSingleElement() == t1 do 3:4231: return CastKind.elemToTup; 4379:4232: if tt1 && asTypeStruct(t2) do 25:4233: return CastKind.tupToStruct; -:4234: -:4235: // only allowed explicitly 4354:4236: if isTrunc && isFromInt && isToInt do 2787:4237: return CastKind.intTrunc; 1567:4238: if isTrunc && isFromFp && isToFp do 16:4239: return CastKind.fpTrunc; 1551:4240: if isFromFp && isToInt do 37:4241: return CastKind.fpToInt; 1514:4242: if tp1 && tp2 do 1361:4243: return CastKind.bitCast; 153:4244: if isFromInt && t1.size == session.ptr_size && tp2 do 8:4245: return CastKind.intToPtr; 145:4246: if tp1 && t2.size == tp1.size do 14:4247: return CastKind.ptrCast; -:4248: 131:4249: return CastKind.invalid; -:4250:} -:4251: -:4252:/// Returns: the kind of complex operator overload for which the input expression can be used -:4253:function getMacroOperatorKind(Expression* e): OpOverloadKind -:4254:{ 10566:4255: if var auto ae = asAssignExp(e) do -:4256: { 5391:4257: if asIndexExp(ae.left) do return OpOverloadKind.indexAssign; 4916:4258: if asSliceExp(ae.left) do return OpOverloadKind.sliceAssign; -:4259: } 4984:4260: return OpOverloadKind.default; -:4261:} -:4262: -:4263:function filterUnderscoresAndNullTerminate(Token* t): s8[+] -:4264:{ -:4265: @return var s8[+] result; 120:4266: const auto text = t.text()[]; 120:4267: var auto c = 0; 120:4268: result.length = text.length + 1; 120:4269: foreach const auto tc in text do 1384:4270: if tc != "_" do result.ptr[c++] = tc; 120:4271: result.ptr[c++] = 0; 120:4272: result.length = c; 120:4273: return result; -:4274:} -:4275: -:4276:/// Returns: if the declaration requires a `this` context, e.g true for non static member variable. -:4277:function needThis(Declaration* node): bool -:4278:{ 52410:4279: return node.symbol.parent.kind in aggregateKinds && !node.isStatic(); -:4280:} -:4281: -:4282:/** Returns: `null` if operator overload is not possible and a CallExpression otherwise. -:4283: * If the result is valid, its semantic is not yet run. */ -:4284:function tryOperatorOverload(Expression* e; Expression*[] args): Expression* -:4285:{ 37660:4286: assert(args.length); 37660:4287: assert(args[0].type, "call tryOperatorOverload after una.exp or bina.left sema"); -:4288: -:4289: // only allowed on custom types or on pointer to custom types (DotExp implicit deref) 37660:4290: var auto tp = args[0].type.asTypePointer(); 37660:4291: var auto ta = tp ? tp.modified.asTypeAggregate() else args[0].type.asTypeAggregate(); 69524:4292: if !ta do return null; -:4293: -:4294: // be sure that the aggregate `hasOpOvers` is defined 5796:4295: if ta.declaration.progress != SemanticProgress.done do -:4296: assert(0, "cannot try opover if aggregate declsema is not run"); -:4297: 5796:4298: var auto ad = ta.declaration; -:4299: 5796:4300: if !ad.hasOpOvers do 1826:4301: return null; -:4302: -:4303: // handle non-overridden opovers -:4304: var Type*[+] chain; 3970:4305: getInheritanceChain(ta, chain); 3970:4306: chain ~= ta; -:4307: 3970:4308: foreach const auto t in chain.reverse do -:4309: { 12566:4310: var auto ts = asTypeAggregate(t).declaration.symbol; 12566:4311: foreach const auto s in ts.children do -:4312: { -:4313: // on every member funcs and overloads ... 94249:4314: var auto fd = symToFuncDecl(s); 94249:4315: var auto od = symToOverDecl(s); 94249:4316: var auto funOrOverDecl = fd ? od; 94249:4317: if !funOrOverDecl do 34350:4318: continue; -:4319: -:4320: // ... that are annotated @operator.... -:4321: var Attribute* oa; 59899:4322: if (oa = funOrOverDecl.getAtOperator()) == null do 54817:4323: continue; -:4324: -:4325: // dont check param count if func is an overload set 5082:4326: var auto parametersMatch = true; 5082:4327: if fd do -:4328: { 5071:4329: if fd.isStatic() do 111:4330: parametersMatch = fd.parameters.length + 1 == args.length; -:4331: else do 4960:4332: parametersMatch = fd.parameters.length == args.length; -:4333: } -:4334: 5082:4335: foreach const auto p in oa.arguments do -:4336: { -:4337: var bool isMacroOp; 10224:4338: if var auto oom = asOpOverloadMacro(p) do 5:4339: isMacroOp = getMacroOperatorKind(e) == oom.kind; -:4340: -:4341: //... that handles the right operator... 5112:4342: if (p.operator == e.operator || isMacroOp) && parametersMatch do -:4343: { 236:4344: var auto po = args[0].startPos; 236:4345: var auto id = (new IdentExpression).create(po, funOrOverDecl.name, fd ? fd.returnType else od.asTypeDeclared, funOrOverDecl.symbol); -:4346: var Expression* callee; 236:4347: if fd && fd.isGeneric() do -:4348: { 2:4349: id.type = args[0].type = null; 2:4350: id.symbol = args[0].symbol = null; 2:4351: var auto tk = identifier(tokenString[p.operator]); 2:4352: var auto se = (new StringExpression).create(po, tk):Expression*; 2:4353: var auto de = (new DotExpression).create(po, args[0], id); 2:4354: var auto ap = (new ApplyExpression).create(po, de, [se]); 2:4355: callee = ap; -:4356: } -:4357: else do -:4358: { 234:4359: var auto de = (new DotExpression).create(po, args[0], id); 234:4360: de.symbol = funOrOverDecl.symbol; 234:4361: de.type = fd ? fd.returnType else od.asTypeDeclared; 234:4362: callee = de; -:4363: } -:4364: 236:4365: var CallExpression* ce = (new CallExpression).create(po, callee); 236:4366: ce.arguments = args[1..$]; -:4367: -:4368: //printf("%s\n", format(ce).ptr); -:4369: -:4370: // ... rewrite as a CallExp 236:4371: ce.isOpOverRewrite = true; 236:4372: return ce; -:4373: } -:4374: } -:4375: } -:4376: } 3734:4377: return null; -:4378:} -:4379: -:4380:/** -:4381: * Replace built-in properties with other expressions. -:4382: * -:4383: * Returns: a new expression if node.dotted is a property, `null` otherwise. -:4384: */ -:4385:function tryProperties(DotExpression* node; Scope* scope): Expression* -:4386:{ -:4387: var bool isMin; 48453:4388: switch asIdentExp(node.dotted).identifier.text() do -:4389: { -:4390: on "min" do -:4391: { 27:4392: isMin = true; 27:4393: continue on; -:4394: } -:4395: on "max" do -:4396: { 610:4397: if var auto te = asTypeEnum(node.expression.type) do 12:4398: return isMin ? te.declaration.min else te.declaration.max; 586:4399: if var auto te = asTypeEnumSet(node.expression.type) do -:4400: { 4:4401: const u64 v = isMin ? 0 else u64.max >> (64 - te.declaration.members.length:u32); 4:4402: return (new IntegerExpression).create(node.startPos, null, v, te); -:4403: } 289:4404: if !node.expression.type.isIntegral() do 12:4405: return null; -:4406: var u64 v; 277:4407: var auto t = node.expression.type.resolved(); 277:4408: switch t.kind do -:4409: { 8:4410: on $s8 do v = isMin ? 0x80:s8 else 0x7F; 4:4411: on $s16 do v = isMin ? 0x8000:s16 else 0x7FFF; 4:4412: on $s32 do v = isMin ? 0x8000_0000:s32 else 0x7FFF_FFFF; 4:4413: on $s64 do v = isMin ? 0x8000_0000_0000_0000:s64 else 0x7FFF_FFFF_FFFF_FFFF; 10:4414: on $u8 do v = isMin ? 0 else 0xFF; 6:4415: on $u16 do v = isMin ? 0 else 0xFFFF; 100:4416: on $u32 do v = isMin ? 0 else 0xFFFF_FFFF; 141:4417: on $u64 do v = isMin ? 0 else 0xFFFF_FFFF_FFFF_FFFF; -:4418: } 277:4419: if t.isSigned() do 20:4420: t = t.size <= 32 ? TypeS32.instance() else TypeS64.instance(); -:4421: else do 257:4422: t = t.size <= 32 ? TypeU32.instance() else TypeU64.instance(); 277:4423: return (new IntegerExpression).create(node.startPos, null, v, t); -:4424: } -:4425: on "length" do -:4426: { 1169:4427: assert(node.expression.type); 1169:4428: var auto t = node.expression.type.resolved(); 1169:4429: if t.kind == tkSlice || t.kind == tkRca do 1110:4430: return (new LengthExpression).create(node.expression, false, TypeUSize()); 118:4431: else do if var auto tsa = asTypeStaticArray(t) do 22:4432: return (new IntegerExpression).create(node.startPos, null, tsa.length(), TypeU32.instance()); 74:4433: else do if var auto tt = asTypeTuple(t) do 4:4434: return (new IntegerExpression).create(node.startPos, null, tt.types.length, TypeU32.instance()); 33:4435: return null; -:4436: } -:4437: on "ptr" do -:4438: { 785:4439: assert(node.expression.type); -:4440: var TypeModified* ta; 785:4441: ta = asTypeStaticArray(node.expression.type); 785:4442: ta ?= asTypeSlice(node.expression.type); 785:4443: ta ?= asTypeRcArray(node.expression.type); 1556:4444: if ta do return (new PtrExpression).create(node.expression, (new TypePointer).create(ta.modified.resolved()), false); 14:4445: return null; -:4446: } -:4447: on "dup" do -:4448: { 14:4449: if var auto tra = asTypeRcArray(node.expression.type) do 6:4450: return (new RefCountExpression).create(node.startPos, node.expression, RefCountOp.dup_, tra); 1:4451: return null; -:4452: } -:4453: on "refcount" do -:4454: { 100:4455: if var auto tra = asTypeRcArray(node.expression.type) do 49:4456: return (new RefCountExpression).create(node.startPos, node.expression, RefCountOp.refcount_, TypeUSize()); 1:4457: return null; -:4458: } -:4459: on "decref" do -:4460: { 162:4461: if var auto tra = asTypeRcArray(node.expression.type) do 80:4462: return (new RefCountExpression).create(node.startPos, node.expression, RefCountOp.decref_, TypeVoid.instance()); 1:4463: return null; -:4464: } -:4465: on "incref" do -:4466: { 6:4467: if var auto tra = asTypeRcArray(node.expression.type) do 2:4468: return (new RefCountExpression).create(node.startPos, node.expression, RefCountOp.incref_, TypeVoid.instance()); 1:4469: return null; -:4470: } -:4471: on "sizeof" do -:4472: { 294:4473: assert(node.expression.type); 294:4474: var auto t = node.expression.type.resolved(); 294:4475: var auto ta = asTypeAggregate(t); 294:4476: if ta do -:4477: { 235:4478: memulate(ta.declaration, ta.declaration.scope); 235:4479: if !ta.declaration.body do -:4480: { 1:4481: session.error(scope.filename, node.startPos, "body-less aggregate `%s` has an unknown size", format(ta).ptr); 1:4482: return null; -:4483: } -:4484: // when member init is resolved, error can be gagged, -:4485: // see git 5bdc76b4d1584e8f3ba8cabeeb281da37f95a543 234:4486: assert(ta.declaration.sizeKnown || session.errorsCount()); -:4487: } 293:4488: const u64 s = isTypeBool(t) ? 1 else t.size / 8; 293:4489: return new (IntegerExpression).create(node.startPos, null, s, TypeU32.instance()); -:4490: } -:4491: on "stringof" do -:4492: { 53:4493: return (new StringExpression).create(node.dotted.startPos, identifier(format(node.expression, internalMode)), (new TypePointer).create(TypeS8.instance())); -:4494: } -:4495: on "expand" do -:4496: { 10:4497: if var auto tt = asTypeTuple(node.expression.type) do -:4498: { -:4499: // Do not use `tt.needsExpansion` because expansion is only possible in TupleExp -:4500: // hence flag could cause an unwanted expansion later e.g `stuff.expand; (0, stuff);`. -:4501: // The dotted part is verified and dropped in `visitTupleExpression()` 4:4502: node.type = tt; 4:4503: return node; -:4504: } 1:4505: return null; -:4506: } -:4507: on "tupleof" do -:4508: { 12:4509: if var auto ts = asTypeStruct(node.expression.type) do -:4510: { 3:4511: var auto s = ts.declaration.symbol; 3:4512: var Expression*[+] exps = (new Expression*[+])(s.children.length); -:4513: var usize i; 3:4514: foreach var auto cs in s.children do -:4515: { 15:4516: var auto vd = symToVarDecl(cs); 15:4517: if !vd || vd.isStatic() do 3:4518: continue; 12:4519: exps[i++] = (new DotExpression).create(node.startPos, node.expression, varToIdentExp(vd), vd.type); -:4520: } 3:4521: exps.length = i; 3:4522: return expressionSemantic((new TupleExpression).create(node.startPos, exps), scope); -:4523: } 3:4524: else do if node.expression.parens do -:4525: { 2:4526: node.expression.parens--; 2:4527: return expressionSemantic((new TupleExpression).create(node.startPos, [node.expression]), scope); -:4528: } 1:4529: return null; -:4530: } 13393:4531: else do return null; -:4532: } -:4533:} -:4534: -:4535:/// Expand in-place the tuple `e` of type `tt` in exps[pos] -:4536:function expandTuple(var Expression* e; var Expression*[+] exps; TypeTuple* tt; const usize pos) -:4537:{ 9:4538: var Expression*[+] tail = exps[pos+1 .. $]; 18:4539: if var auto te = asTupleExp(e) do -:4540: { 3:4541: exps = exps[0 .. pos] ~ te.expressions; -:4542: } -:4543: else do -:4544: { 6:4545: exps = exps[0 .. pos]; 6:4546: exps.length += tt.types.length; 6:4547: foreach (const auto j; var auto t) in tt.types do 12:4548: exps.ptr[pos + j] = (new IndexExpression).create(e.startPos, e, (new IntegerExpression).create(e.startPos, null, j, TypeUSize()), t); -:4549: } 9:4550: exps ~= tail; 9:4551:} -:4552: -:4553:/// Expand in-place the tuples marked with `.expand` -:4554:function expandTuples(var Expression*[+] exps; usize from) -:4555:{ 11571:4556: foreach (const auto i; const auto e) in exps[from .. $] do -:4557: { 18652:4558: var auto tt = asTypeTuple(e.type); 18652:4559: if !tt do 18620:4560: continue; 32:4561: var auto de = asDotExp(e); 32:4562: var auto id = de ? asIdentExp(de.dotted) else null; 32:4563: const auto needExpansion = id && id.identifier.iptr() == propExpandToken().iptr(); 32:4564: if needExpansion do -:4565: { 4:4566: from = i + tt.types.length; 4:4567: expandTuple(de.expression, exps, tt, i); 4:4568: expandTuples(exps, from); 4:4569: return; -:4570: } -:4571: } 11567:4572:} -:4573: -:4574:/// Returns: If `ce` arguments can be used to apply the generic `fd`, the matching generic application, else `null` -:4575:function tryGenericApplicationFromArg(FunctionDeclaration* fd; CallExpression* ce; Scope* scope): FunctionDeclaration* -:4576:{ 33:4577: var auto na = ce.arguments.length; 33:4578: var auto pos = ce.startPos; 33:4579: var auto de = asDotExp(ce.expression); -:4580: -:4581: var usize numGenericParam; -:4582: var usize nd; -:4583: 33:4584: foreach var auto p in fd.genericParameters.parameters do 46:4585: numGenericParam += !p.applied(); 33:4586: foreach var auto p in fd.parameters.reverse do -:4587: { 39:4588: if !p.initializer do 31:4589: break; 8:4590: nd++; -:4591: } -:4592: -:4593: // Type.callee(args) -> callee:[Type](args) 33:4594: if de do -:4595: { 16:4596: var Expression* te = asTypeExp(de.expression); 16:4597: if te && fd.symbol.parent.kind !in aggregateKinds do -:4598: { 3:4599: var auto ae = (new ApplyExpression).create(pos, de.dotted, [te]); 3:4600: var auto og = session.startGagging(); 3:4601: var auto e = expressionSemantic(ae, scope); 3:4602: if og == session.stopGagging() do -:4603: { 3:4604: ce.expression = e; 3:4605: return symToFuncDecl(ae.symbol); -:4606: } -:4607: } -:4608: } -:4609: -:4610: // callee(args) -> callee:[args.types](); 30:4611: const bool tryStraightCall = (!de || fd.isStatic() && fd.symbol.parent == de.expression.symbol) && na + nd >= numGenericParam; -:4612: // arg0.callee(argsTail) -> callee:[arg0.type, argsTail.types]() 30:4613: var bool tryUFCall = !tryStraightCall && de && na + 1 + nd >= numGenericParam; -:4614: 30:4615: if tryStraightCall || tryUFCall do -:4616: { 28:4617: var auto tes = (new Expression*[+])(numGenericParam); -:4618: 28:4619: var auto cas = tryUFCall ? de.expression ~ ce.arguments else ce.arguments; 28:4620: var auto callee = tryUFCall ? &de.dotted else &ce.expression; 28:4621: var auto numGpDone = 0; -:4622: 28:4623: foreach (const auto fpIndex; const auto fp) in fd.parameters do -:4624: { -:4625: // parameters sema is not executed so the type of a function parameter -:4626: // that's for a generic parameter is always a TypeId 46:4627: var auto te = asTypeIdentifier(fp.type); 55:4628: if !te do continue; -:4629: -:4630: // find which generic parameter the function parameter is for 37:4631: var ssize gpIndex = -1; -:4632: var usize i; 37:4633: foreach var auto gp in fd.genericParameters.parameters do -:4634: { 53:4635: if gp.applied() do continue; 47:4636: if !tes.ptr[i] && te.identifier.iptr() == gp.name.iptr() do 37:4637: break gpIndex = i; 10:4638: i++; -:4639: } -:4640: -:4641: // The TypeId is not for a generic parameter 37:4642: if gpIndex == -1 do continue; -:4643: -:4644: // take the expression that will be used to apply 37:4645: var auto ca = fpIndex < cas.length ? cas[fpIndex] else null; 37:4646: if !ca && fp.initializer do -:4647: { 4:4648: fp.initializer = expressionSemantic(fp.initializer, scope.pushNested()); 4:4649: ca = fp.initializer; -:4650: } 37:4651: tes.ptr[gpIndex] = (new TypeExpression).create(pos, ca ? ca.type else TypeError.instance(), true); 37:4652: numGpDone++; -:4653: } -:4654: 28:4655: if numGpDone == numGenericParam do -:4656: { 27:4657: var auto ae = (new ApplyExpression).create(pos, *callee, tes); 27:4658: var auto og = session.startGagging(); 27:4659: var auto e = expressionSemantic(ae, scope); 27:4660: if og == session.stopGagging() do -:4661: { 27:4662: *callee = e; 27:4663: return symToFuncDecl(ae.symbol); -:4664: } -:4665: } -:4666: } -:4667: 3:4668: return null; -:4669:} <<<<<< EOF # path=src/styx/semantic/imports.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/semantic/imports.sx -: 1:unit styx.semantic.imports; -: 2: -: 3:@private import -: 4: styx.session, -: 5: styx.token, -: 6: styx.ast.base, -: 7: styx.ast.declarations, -: 8: styx.ast.formatter, -: 9: styx.ast.statements, -: 10: styx.ast.types, -: 11: styx.ast.visitor, -: 12: styx.semantic, -: 13: styx.scope, -: 14: styx.symbol, -: 15: system, -: 16: ; -: 17: -: 18:/// Binds ImportDeclaration to their matching units. -: 19:function attachImports(UnitDeclaration* node) -: 20:{ -: 21: var ImportAttacher ia; 488: 22: ia.visitUnitDeclaration(node); 488: 23:} -: 24: -: 25:/// Binds ImportDeclaration to their matching units. -: 26:function attachDeclarationImports(Declaration* node) -: 27:{ -: 28: var ImportAttacher ia; 238: 29: ia.scope = node.scope; 238: 30: ia.$unit = node.scope.sym.parentUnit(); 238: 31: ia.visitConcreteDeclaration(node); 238: 32:} -: 33: -: 34:protection(private) -: 35: -: 36:class ImportAttacher : AstVisitor -: 37:{ -: 38: var Scope* scope; -: 39: var UnitDeclaration* $unit; -: 40: -: 41: function addLexerParserPairForImport(TypeIdentifier* tid): LexerParserPair* -: 42: { 9: 43: foreach var auto importPath in session.imports do -: 44: { 6: 45: var auto path = importPath; 6: 46: if path[$-1] != "/" do 6: 47: path ~= "/"; 6: 48: while true do -: 49: { 7: 50: path ~= tid.identifier.text(); 7: 51: if !tid.next do -: 52: { 6: 53: path ~= ".sx\0" ; 6: 54: if exists(path) do 4: 55: return (new LexerParserPair).createForFile(path, true); 2: 56: break; -: 57: } -: 58: else do -: 59: { 1: 60: path ~= "/"; 1: 61: tid = tid.next; -: 62: } -: 63: } -: 64: } 5: 65: return null; -: 66: } -: 67: -: 68: function getUnitForChain(TypeIdentifier* tid; AstNode* node): Symbol* -: 69: { 424: 70: var auto tid0 = tid; 424: 71: var Symbol* result = Root.instance(); 424: 72: while true do -: 73: { 850: 74: var Symbol* c = result.find(tid.identifier, unitKinds); 850: 75: result = null; -: 76: // access chain, either a temp dotUnit unit or a real one 850: 77: if tid.next && c do -: 78: { 426: 79: result = c; 426: 80: tid = tid.next; 426: 81: continue; -: 82: } -: 83: // last chain elem must be a real unit 424: 84: else do if !tid.next && c && c.kind == SymbolKind.$unit do 415: 85: result = c; -: 86: // else no matching source was parsed 9: 87: else do result = null; 424: 88: break; -: 89: } 424: 90: if !result do -: 91: { 18: 92: if var auto p = addLexerParserPairForImport(tid0) do -: 93: { 4: 94: session.lexerParserPairs ~= p; 4: 95: if session.verbose do printf("parsing %s...\n", p.filename.ptr); 8: 96: if var auto u = p.parser.parseUnitDeclaration() do -: 97: { 4: 98: if session.verbose do printf("pre-semantic for %s...\n", p.filename.ptr); 4: 99: if preSemantic(u) do -:100: { 4:101: if session.verbose do printf("attaching imports for %s...\n", p.filename.ptr); 4:102: if linkImports(u) do 4:103: result = u.symbol; -:104: } -:105: } -:106: } -:107: } 424:108: if !result do -:109: { 5:110: error(scope.filename, node.startPos, "cannot find imported unit `%s`", format(tid0).ptr); 5:111: return null; -:112: } -:113: 419:114: var UnitDeclaration* ud = result.astNode:UnitDeclaration*; 419:115: if ud.filename == $unit.filename do -:116: { 2:117: error(scope.filename, node.startPos, "the unit imports itself"); 2:118: return null; -:119: } 417:120: if session.verbose do -:121: { 3:122: printf("binded import `%s` declared in `%s`\n", format(tid0).ptr, $unit.filename.ptr); -:123: } 417:124: return result; -:125: } -:126: -:127: function visitAggregateDeclaration(AggregateDeclaration* node) -:128: { 1050:129: var auto old = scope; 1050:130: scope = node.scope; 1050:131: node.accept(this); 1050:132: scope = old; 1050:133: } -:134: -:135: @override function visitBlockStatement(BlockStatement* node) -:136: { 13592:137: if node.noScope do -:138: { 26:139: node.accept(this); 26:140: return; -:141: } 13566:142: var auto old = scope; 13566:143: scope = node.scope; 13566:144: node.accept(this); 13566:145: scope = old; 13566:146: } -:147: -:148: @override function visitClassDeclaration(ClassDeclaration* node) -:149: { 491:150: visitAggregateDeclaration(node); 491:151: } -:152: -:153: @override function visitDeclaration(Declaration* node) -:154: { 23848:155: switch node.kind do -:156: { -:157: on $class, $struct, $function, $union, $import, $version do 6794:158: visitConcreteDeclaration(node); 17054:159: else do {} -:160: } 23848:161: } -:162: 25312:163: @override function visitExpression(Expression* node){} -:164: -:165: @override function visitImportDeclaration(ImportDeclaration* node) -:166: { 197:167: const usize first = node.isSelective ? node.importList.length - 1 else 0; 197:168: foreach var auto ti in node.importList[0 .. first] do -:169: { 17:170: if ti.next do 1:171: error(scope.filename, ti.startPos, "the selection must be a single identifier"); -:172: } 197:173: foreach const auto list in node.importList[first .. $] do -:174: { -:175: var ImportElement* e; -:176: var ImportElement* f; 424:177: var Symbol* s = scope.sym; 424:178: var TypeIdentifier* tid = list; -:179: 424:180: node.symbol = getUnitForChain(tid, list); 424:181: while tid do -:182: { 1704:183: if var Symbol* r = s.find(tid.identifier, SymbolKind.$import) do 535:184: e = *((&r):ImportElement**); -:185: else do 317:186: e = (new ImportElement).create(tid.identifier, s, null); 852:187: f ?= e; 852:188: e.$protection = node.$protection; 852:189: e.startPos = tid.startPos; 852:190: e.astNode = list; 852:191: tid = tid.next; 852:192: s = e; 852:193: if !tid do -:194: { 424:195: if !e.terminalUnit do 424:196: f.nonQualified ~= e; 424:197: e.terminalUnit = node.symbol; 424:198: if first do -:199: { 16:200: e.selection.length = first; 16:201: foreach (const auto i; var auto t) in node.importList[0 .. first] do 17:202: e.selection[i] = asTypeIdentifier(t).identifier; -:203: } -:204: } -:205: } -:206: } 197:207: if node.symbol do 191:208: foreach var auto ti in node.importList[0 .. first] do -:209: { 16:210: var auto s = node.symbol.searchStrict(ti.identifier, ti.startPos, $unit.scope.sym); 16:211: if !s do 1:212: error(scope.filename, ti.startPos, "identifier `%s` not found in target unit", ti.identifier.text().ptr); -:213: } 197:214: } -:215: -:216: @override function visitUnitDeclaration(UnitDeclaration* node) -:217: { 488:218: scope = node.scope; 488:219: $unit = node; 488:220: node.accept(this); 488:221: } -:222: -:223: @override function visitStructDeclaration(StructDeclaration* node) -:224: { 531:225: visitAggregateDeclaration(node); 531:226: } -:227: 5720:228: @override function visitType(Type* node){} -:229: -:230: @override function visitUnionDeclaration(UnionDeclaration* node) -:231: { 28:232: visitAggregateDeclaration(node); 28:233: } -:234:} <<<<<< EOF # path=src/styx/semantic/memulator.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/semantic/memulator.sx -: 1:unit styx.semantic.memulator; -: 2: -: 3:@private import -: 4: styx.ast.base, -: 5: styx.ast.declarations, -: 6: styx.ast.formatter, -: 7: styx.ast.types, -: 8: styx.ast.visitor, -: 9: styx.position, -: 10: styx.session, -: 11: styx.symbol, -: 12: styx.scope, -: 13: ; -: 14: -: 15:/** -: 16: * construct the memory layout of aggregates and their members. -: 17: * -: 18: * - set the `TypeAggregate.size`. -: 19: * - set the `VariableDeclaration.offset` if it's a non-static member. -: 20: * -: 21: * special wink to #proglangdesign for the name... -: 22: */ -: 23:function memulate(Declaration* node; Scope* scope) -: 24:{ -: 25: var Memulator m; 4008: 26: m.scope = scope; 4008: 27: m.visitConcreteDeclaration(node); 4008: 28:} -: 29: -: 30:function memulateTypeTuple(Type* node; Scope* scope) -: 31:{ -: 32: var Memulator m; 215: 33: m.scope = scope; 215: 34: m.visitConcreteType(node); 215: 35:} -: 36: -: 37:protection (private) -: 38: -: 39:@final class Memulator : AstVisitor -: 40:{ -: 41: var u32 size; -: 42: var bool of; -: 43: var bool isProcessingTypeTuple; -: 44: var Scope* scope; -: 45: var bool inUnion; -: 46: -: 47: function setTypeAlign(Type* node) -: 48: { 1166: 49: switch node.size do -: 50: { 278: 51: on 8 do node.align = 0; 3: 52: on 16 do node.align = -node.size & 15; 76: 53: on 32 do node.align = -node.size & 31; 809: 54: else do node.align = -node.size & (session.ptr_size - 1):u32; -: 55: } 1166: 56: } -: 57: -: 58: @override function visitClassDeclaration(ClassDeclaration* node) -: 59: { 2366: 60: if of || node.sizeKnown || node.isGeneric() do 1895: 61: return; -: 62: 471: 63: node.symbol.recurseGuard++; 471: 64: const auto old = size; 471: 65: size = session.ptr_size; // vtable 471: 66: if node.inheritanceList.length do -: 67: { 656: 68: if var TypeClass* tc = node.inheritanceList[0].asTypeClass() do -: 69: { 327: 70: if !session.errorsCount() do 297: 71: memulate(tc.declaration, tc.declaration.scope); 327: 72: size += tc.size - session.ptr_size; -: 73: } -: 74: } 471: 75: node.accept(this); 471: 76: node.asTypeDeclared.size = size == 0 ? 8:u32 else size; 471: 77: setTypeAlign(node.asTypeDeclared); 471: 78: node.sizeKnown = true; -: 79: -: 80: //import styx.token; -: 81: //printf("%s=%d\n", (node.symbol.fqn(true).tokenChainText() ~ "\0").ptr, size / 8); -: 82: 471: 83: size = old; 471: 84: node.symbol.recurseGuard--; 471: 85: } -: 86: -: 87: @override function visitFunctionDeclaration(FunctionDeclaration* node) -: 88: { 2124: 89: } -: 90: -: 91: @override function visitTypeTuple(TypeTuple* node) -: 92: { 215: 93: if of do 0: 94: return; -: 95: 215: 96: const auto old1 = size; 215: 97: const auto old2 = isProcessingTypeTuple; 215: 98: size = 0; 215: 99: isProcessingTypeTuple = true; 215:100: foreach const auto t in node.types do 475:101: addField(t); 215:102: node.size = size; 215:103: setTypeAlign(node); 215:104: size = old1; 215:105: isProcessingTypeTuple = old2; 215:106: } -:107: -:108: @override function visitStructDeclaration(StructDeclaration* node) -:109: { 1648:110: if of || node.sizeKnown || node.isGeneric() do 1195:111: return; -:112: 453:113: node.symbol.recurseGuard++; 453:114: const auto old = size; 453:115: size = 0; 453:116: node.accept(this); 453:117: node.asTypeDeclared.size = size == 0 ? 8:u32 else size; 453:118: setTypeAlign(node.asTypeDeclared); 453:119: node.sizeKnown = true; 453:120: size = old; 453:121: node.symbol.recurseGuard--; 453:122: } -:123: -:124: @override function visitUnionDeclaration(UnionDeclaration* node) -:125: { 36:126: if of || node.sizeKnown || node.isGeneric() do 9:127: return; -:128: 27:129: node.symbol.recurseGuard++; 27:130: const auto oldSize = size; 27:131: const auto oldInUnion = inUnion; 27:132: size = 0; 27:133: inUnion = true; 27:134: node.accept(this); 27:135: node.asTypeDeclared.size = size; 27:136: setTypeAlign(node.asTypeDeclared); 27:137: node.sizeKnown = true; 27:138: inUnion = oldInUnion; 27:139: size = oldSize; 27:140: node.symbol.recurseGuard--; 27:141: } -:142: -:143: function hasCircularThings(var Position p; Type* t): bool -:144: { 1344:145: static const auto spec = "cannot determine the size of `%s` because of a circular reference"; -:146: 2688:147: if var TypeAggregate* ta = asTypeAggregate(t) do -:148: { 44:149: if !ta.declaration.sizeKnown do -:150: { 20:151: if ta.declaration.symbol.recurseGuard > 0 do -:152: { 9:153: error(scope.filename, p, spec, format(ta.declaration).ptr); 9:154: return true; -:155: } 11:156: visitConcreteDeclaration(ta.declaration); -:157: } -:158: } 2600:159: else do if var TypeIdentifier* ti = asTypeIdentifier(t) do -:160: { 0:161: if !ti.isSolved() do -:162: { 0:163: error(scope.filename, p, spec, format(ti).ptr); 0:164: return true; -:165: } -:166: } 2600:167: else do if var TypeStaticArray* tsa = asTypeStaticArray(t) do -:168: { 29:169: return hasCircularThings(p, tsa.modified.resolved()); -:170: } 1306:171: return false; -:172: } -:173: -:174: @override function visitVariableDeclaration(VariableDeclaration* node) -:175: { 983:176: if node.isStatic() do 143:177: return; 840:178: addField(node.type, node); 840:179: } -:180: -:181: function addField(Type* t; VariableDeclaration* vd = null) -:182: { 1315:183: if of do 0:184: return; 1315:185: t = t.resolved(); 1315:186: var Position p = vd ? vd.startPos else t.startPos; 1315:187: if hasCircularThings(p, t) do 9:188: return; -:189: -:190: // that's an error in declsema or will be when using a TypeTuple as VarDEcl 1306:191: if !t.isVariableType() do 12:192: return; -:193: // so that .sizeof can return Type.size / 8 1294:194: if isTypeBool(t) do 85:195: t = TypeU8.instance(); -:196: 1294:197: const u32 nextSize = t.size; -:198: 1294:199: if !inUnion do -:200: { -:201: var u32 pad; 1260:202: var TypeAggregate* ta = asTypeAggregate(t); 1260:203: var TypeEnumSet* tes = asTypeEnumSet(t); 1260:204: var TypeModified* tm = tes ? null else asTypeModified(t); 1260:205: var TypeTuple* tt = asTypeTuple(t); 1260:206: if ta || tm || tt || nextSize == session.ptr_size do 707:207: pad = -size & (session.ptr_size-1):u32; 553:208: else do switch nextSize do -:209: { 1:210: on 64 do pad = 0; // -m32 375:211: on 32 do pad = -size & 31; 25:212: on 16 do pad = -size & 15; 151:213: on 8 do {} -:214: else do -:215: { 1:216: if !session.errorsCount() do -:217: assert(0, "unexpected non-static member with no size"); 1:218: return; -:219: } -:220: } 1259:221: assert(pad < session.ptr_size); 2051:222: if vd do vd.offset = size + pad; 1259:223: var u64 tmp = size:u64 + (nextSize + pad); 1259:224: of = tmp > u32.max; 1259:225: if of && vd do 1:226: error(scope.filename, p, "`%s` causes its parent aggregate size to cross the limit of `%d` bytes", format(vd).ptr, u32.max / 8); 1258:227: else do if of do assert(0, "TypeTuple size overflowing"); 1259:228: size = tmp:u32; -:229: } -:230: else do -:231: { 34:232: vd.offset = 0; 34:233: size = t.size > size ? t.size else size; -:234: } 1293:235: } -:236:} -:237: <<<<<< EOF # path=src/styx/semantic/protection.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/semantic/protection.sx -: 1:unit styx.semantic.$protection; -: 2: -: 3:@private import -: 4: styx.position, -: 5: styx.token, -: 6: styx.ast.base, -: 7: styx.ast.declarations, -: 8: styx.ast.visitor, -: 9: styx.scope, -: 10: ; -: 11: -: 12:/// Apply the `ProtectionDeclaration` to each `Declaration` of the provided unit -: 13:function setProtections(UnitDeclaration* node) -: 14:{ -: 15: static var NodeProtectionVisitor npv; 505: 16: npv.scope = node.scope; 505: 17: npv.visitUnitDeclaration(node); 505: 18:} -: 19: -: 20:protection(private) -: 21: -: 22:class NodeProtectionVisitor : AstVisitor -: 23:{ -: 24: var bool inDerivable; -: 25: var Protection currProt; -: 26: var Scope* scope; -: 27: var AstNode* illegalScope; -: 28: -: 29: function identifierToProt(Token* tok; var Position p) -: 30: { 251: 31: if illegalScope do -: 32: { 4: 33: var auto t = tok.text(); 4: 34: error(scope.filename, p, "`protection(%s)` or `@%s` is only allowed in `class`, `struct`, `union`, and `unit` scopes", t.ptr, t.ptr); -: 35: } 251: 36: const auto i = tok.iptr(); 251: 37: if i == publicToken().iptr() do -: 38: { 95: 39: overwriteProtection(Protection.public); -: 40: } 156: 41: else do if i == protectedToken().iptr() do -: 42: { 5: 43: overwriteProtection(Protection.protected); 5: 44: if !inDerivable do 3: 45: warn(scope.filename, p, "in non-derivable aggregates `protected` is equivalent to `private`"); -: 46: } 151: 47: else do if i == privateToken().iptr() do -: 48: { 134: 49: overwriteProtection(Protection.private); -: 50: } 17: 51: else do if i == strictToken().iptr() do -: 52: { 16: 53: overwriteProtection(Protection.strict); -: 54: } 1: 55: else do error(scope.filename, p, -: 56: "`%s` is not a valid protection, expected `public`, `protected`, `private` or `strict`", -: 57: tok.text().ptr); 251: 58: } -: 59: -: 60: function pushProtection(const Protection value): Protection -: 61: { 6114: 62: var auto result = currProt; 6114: 63: currProt = value; 6114: 64: return result; -: 65: } -: 66: -: 67: function overwriteProtection(const Protection value) -: 68: { 250: 69: currProt = value; 250: 70: } -: 71: -: 72: function popProtection(const Protection previous) -: 73: { 6114: 74: currProt = previous; 6114: 75: } -: 76: -: 77: function setField(Declaration* node) -: 78: { 12314: 79: node.$protection = currProt; 12314: 80: } -: 81: -: 82: @override function visitAliasDeclaration(AliasDeclaration* node) -: 83: { 348: 84: setField(node); 348: 85: } -: 86: -: 87: @override function visitClassDeclaration(ClassDeclaration* node) -: 88: { 480: 89: const auto prevInDerivable = inDerivable; 480: 90: const auto prevIllegalScope = illegalScope; 480: 91: illegalScope = null; 480: 92: inDerivable = true; 480: 93: setField(node); 480: 94: const auto p = pushProtection(Protection.public); 480: 95: node.accept(this); 480: 96: popProtection(p); 480: 97: inDerivable = prevInDerivable; 480: 98: illegalScope = prevIllegalScope; 480: 99: } -:100: -:101: @override function visitDeclaration(Declaration* node) -:102: { 13132:103: const auto old = currProt; 13132:104: var auto p = node.getAtProtection(); 13216:105: if p do identifierToProt(p.identifier, p.startPos); 13132:106: super(node); 13216:107: if p do currProt = old; 13132:108: } -:109: -:110: @override function visitEnumDeclaration(EnumDeclaration* node) -:111: { 436:112: setField(node); 436:113: } -:114: -:115: @override function visitExpression(Expression* node) -:116: { 103:117: } -:118: -:119: @override function visitFunctionDeclaration(FunctionDeclaration* node) -:120: { 5168:121: setField(node); 5168:122: const auto p = pushProtection(Protection.public); 5168:123: if node.body do 4478:124: visitConcreteStatement(node.body); 5168:125: popProtection(p); 5168:126: } -:127: -:128: @override function visitImportDeclaration(ImportDeclaration* node) -:129: { 193:130: setField(node); 193:131: node.accept(this); 193:132: } -:133: -:134: @override function visitOverloadDeclaration(OverloadDeclaration* node) -:135: { 45:136: setField(node); 45:137: } -:138: -:139: @override function visitProtectionDeclaration(ProtectionDeclaration* node) -:140: { 167:141: identifierToProt(node.$protection, node.startPos); 167:142: } -:143: -:144: @override function visitStatement(Statement* node) -:145: { 16870:146: const auto prevIllegalScope = illegalScope; 16870:147: illegalScope = node; 16870:148: if node.kind == leftCurly || node.kind == eopDecl do 4877:149: visitConcreteStatement(node); 16870:150: illegalScope = prevIllegalScope; 16870:151: } -:152: -:153: @override function visitStructDeclaration(StructDeclaration* node) -:154: { 440:155: const auto prevInDerivable = inDerivable; 440:156: const auto prevIllegalScope = illegalScope; 440:157: illegalScope = null; 440:158: inDerivable = false; 440:159: setField(node); 440:160: const auto p = pushProtection(Protection.public); 440:161: node.accept(this); 440:162: popProtection(p); 440:163: inDerivable = prevInDerivable; 440:164: illegalScope = prevIllegalScope; 440:165: } -:166: -:167: @override function visitType(Type* node) -:168: { 1160:169: node.accept(this); 1160:170: } -:171: -:172: @override function visitUnionDeclaration(UnionDeclaration* node) -:173: { 26:174: const auto prevInDerivable = inDerivable; 26:175: const auto prevIllegalScope = illegalScope; 26:176: illegalScope = null; 26:177: inDerivable = false; 26:178: setField(node); 26:179: const auto p = pushProtection(Protection.public); 26:180: node.accept(this); 26:181: popProtection(p); 26:182: inDerivable = prevInDerivable; 26:183: illegalScope = prevIllegalScope; 26:184: } -:185: -:186: @override function visitUnitDeclaration(UnitDeclaration* node) -:187: { 505:188: currProt = public; 505:189: node.accept(this); 505:190: } -:191: -:192: @override function visitVariableDeclaration(VariableDeclaration* node) -:193: { 5178:194: setField(node); 5178:195: } -:196:} <<<<<< EOF # path=src/styx/semantic/statements.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/semantic/statements.sx -: 1:unit styx.semantic.statements; -: 2: -: 3:@private import -: 4: styx.ast.base, -: 5: styx.ast.declarations, -: 6: styx.ast.expressions, -: 7: styx.ast.statements, -: 8: styx.ast.types, -: 9: styx.ast.visitor, -: 10: styx.ast.formatter, -: 11: styx.position, -: 12: styx.semantic.declarations, -: 13: styx.semantic.expressions, -: 14: styx.scope, -: 15: styx.session, -: 16: styx.symbol, -: 17: styx.token, -: 18: ; -: 19: -: 20:function statementSemantic(const Statement* node; const Scope* scope) -: 21:{ 7064: 22: var auto ss = StatementSemantics.create(scope); 7064: 23: ss.visitStatement(node); 7064: 24:} -: 25: -: 26:protection(private) -: 27: -: 28:@final class StatementSemantics : AstVisitor -: 29:{ -: 30: var Scope* scope; -: 31: var bool reachable; -: 32: -: 33: import evaluate in styx.semantic.evaluate; -: 34: -: 35: @constructor function create(const Scope* scope) -: 36: { 7064: 37: this.scope = scope; 7064: 38: this.reachable = true; 7064: 39: } -: 40: -: 41: @override function visitAssertStatement(AssertStatement* node) -: 42: { 1865: 43: node.unoptimized = node.expression; 1865: 44: scope = scope.pushNested(); 2118: 45: if node.isStatic do scope.flags += isInInitializer; 1865: 46: node.expression = expressionSemantic(node.expression, scope); 1865: 47: scope = scope.pop(); -: 48: var bool unreachable; 3730: 49: if var auto ie = asIntegerExp(node.expression) do // this includes BoolExps 406: 50: unreachable = ie.value == 0; 3730: 51: if var auto e = toCondition(node.expression, scope) do 1862: 52: node.expression = e; 1865: 53: node.flow = Flow.create(unreachable ? FlowKind.isReturn else FlowKind.isNext); -: 54: 1865: 55: if node.message do -: 56: { 35: 57: scope = scope.pushNested(); 35: 58: node.message = expressionSemantic(node.message, scope); 35: 59: scope = scope.pop(); 35: 60: if node.isStatic do -: 61: { 2: 62: if node.message.operator != TokenType.stringLiteral do 1: 63: error(scope.filename, node.startPos, "optional assert message `%s` cannot be simplified to a string literal", format(node.message).ptr); -: 64: } 33: 65: else do node.message = implicitConvTo(node.message, (new TypePointer).create(TypeS8.instance()), scope); -: 66: } 1830: 67: else do if node.isStatic || !unreachable do 1580: 68: node.message = (new StringExpression).create(node.startPos, identifier(format(node.unoptimized)), (new TypePointer).create(TypeS8.instance())); 1865: 69: reachable = !unreachable; -: 70: 1865: 71: if node.isStatic do -: 72: { 506: 73: if var auto result = evaluate(node.expression) do -: 74: { 231: 75: if !asBoolExp(result).value do 13: 76: error(scope.filename, node.startPos, "static assert failure, `%s`", asStringExp(node.message).value.text().ptr); -: 77: } 22: 78: else do error(scope.filename, node.startPos, "static assert could not be verified during compilation"); 253: 79: return; -: 80: } 1612: 81: } -: 82: -: 83: @override function visitBlockStatement(BlockStatement* node) -: 84: { 12609: 85: var auto wasReachable = reachable; 12609: 86: reachable = true; 12609: 87: if !node.noScope do -: 88: { 12585: 89: scope = scope.pushSym(node.symbol); 12585: 90: scope.tempOwner = node.symbol; -: 91: } -: 92: 12609: 93: if !node.statements.length do 439: 94: node.flow = Flow.create(FlowKind.isNext); 12609: 95: foreach var auto s in node.statements do -: 96: { 59412: 97: if var auto ds = asDeclarationStatement(s) do -: 98: { -: 99: import bodySemantic in styx.semantic.bodies; 6051: 100: declarationSemantic(ds.declaration, scope); 12102: 101: if var auto fd = symToFuncDecl(ds.declaration.symbol) do 235: 102: if isNested in fd.flags do 87: 103: bodySemantic(fd); 6051: 104: if ds.declaration.kind == TokenType.$label do 13: 105: reachable = true; 6051: 106: if !reachable do 3: 107: error(scope.filename, ds.startPos, "declaration is not reachable"); 6051: 108: node.flow.mixLinear(s.flow); -: 109: } -: 110: else do -: 111: { 23655: 112: visitStatement(s); -: 113: // pull the `if ... else` reachable block 23655: 114: var auto ie = asIfElseStatement(s); 23655: 115: if ie && ie.conditionValue != undef do -: 116: { 50: 117: if (s = ie.conditionValue == $false ? ie.elseBlock else ie.thenBlock) do 37: 118: visitStatement(s); -: 119: // replace with an empty block for `if false do ... ;` 50: 120: s ?= (new BlockStatement).create(node.startPos); -: 121: } 23655: 122: if s.kind == leftCurly do -: 123: { 100: 124: node.flow = s.flow; 100: 125: wasReachable = !node.flow.isReturn(); 100: 126: reachable = wasReachable; -: 127: } 23555: 128: else do node.flow.mixLinear(s.flow); 23655: 129: if s.containsNoReturn do -: 130: { 10: 131: node.flow.mixLinear(Flow.create(FlowKind.isReturn)); 10: 132: if node.scope.sym.parent.kind == $function do 3: 133: node.flow.mixLinear(Flow.create(FlowKind.isNoReturn)); -: 134: // reachable diag depends on the previous statement -: 135: // which cant work for func bodies 10: 136: reachable = false; -: 137: } -: 138: } -: 139: } 12609: 140: if !node.noScope do -: 141: { 12585: 142: if node.flow.isContinueToNext() || node.flow.isReturn() do 11578: 143: node.managedLocals = getBlockManagedLocals(node.symbol, node.stopPos); 12585: 144: scope = scope.pop(); -: 145: } 12609: 146: reachable = wasReachable; 12609: 147: } -: 148: -: 149: @override function visitBreakOnStatement(BreakOnStatement* node) -: 150: { 7: 151: var auto sw = scope.$switch; 7: 152: if !sw do 1: 153: return error(scope.filename, node.startPos, "`break on` may only be located inside a `switch`"); 6: 154: sw.breakOns ~= node; 6: 155: node.managedLocals = getParentManagedLocals(node, scope.sym); 6: 156: reachable = false; 6: 157: } -: 158: -: 159: @override function visitBreakStatement(BreakStatement* node) -: 160: { 867: 161: if !(node.target = scope.loop) do 2: 162: error(scope.filename, node.startPos, "`%s` may only be located inside a `foreach` or a `while` body", tokenString[node.kind].ptr); -: 163: 867: 164: if node.expression do -: 165: { 240: 166: scope = scope.pushNested(); 240: 167: node.expression = expressionSemantic(node.expression, scope); 240: 168: scope = scope.pop(); -: 169: } 867: 170: if node.$label do -: 171: { 9: 172: var auto p = (0xFFFFFF, 0):Position; 9: 173: var auto s = scope.sym.searchWild(node.$label, p, scope.sym); 9: 174: if s && s.kind == SymbolKind.$label do -: 175: { -: 176: // link to the while/foreach where the label is declared. -: 177: // the label is only a semantic symbol, unless used by another goto 7: 178: var auto loopScope = scope.getScopeWithSym(s.parent); 7: 179: if !loopScope || !loopScope.loop do 2: 180: error(scope.filename, node.startPos, "the matching `label %s` must be declared in a parent loop body", node.$label.text().ptr); -: 181: else do 5: 182: node.symbol = loopScope.loop.symbol; -: 183: } 2: 184: else do error(scope.filename, node.startPos, "cannot find matching `label %s`", node.$label.text().ptr); -: 185: } 867: 186: node.managedLocals = getParentManagedLocals(node, scope.sym); 867: 187: reachable = false; 867: 188: } -: 189: -: 190: @override function visitStatement(Statement* node) -: 191: { 38755: 192: scope.currentStatement = node; 38778: 193: if !reachable do error(scope.filename, node.startPos, "statement is not reachable"); 38755: 194: super(node); 38755: 195: } -: 196: -: 197: @override function visitContinueStatement(const ContinueStatement* node) -: 198: { 209: 199: visitBreakStatement(*((&node):BreakStatement**)); 209: 200: } -: 201: -: 202: @override function visitContinueOnStatement(ContinueOnStatement* node) -: 203: { 25: 204: var auto sw = scope.$switch; 25: 205: if !sw do 1: 206: return error(scope.filename, node.startPos, "`continue on` statements must be located in a switch"); 24: 207: reachable = false; 24: 208: sw.continueOns ~= node; 24: 209: if !node.targetMatch do -: 210: { 14: 211: if !node.isElseTargeted do -: 212: { 4: 213: foreach const auto oms in sw.onMatchStatements do 14: 214: if oms.startPos > node.startPos do -: 215: { 3: 216: node.realTarget = oms; 3: 217: return; -: 218: } -: 219: } -: 220: else do -: 221: { 10: 222: if !sw.elseBlock do 1: 223: return error(scope.filename, node.startPos, "cannot `continue on else` without explicit `else` block"); 9: 224: if isInSwitchElse in scope.flags do 1: 225: return error(scope.filename, node.startPos, "cannot `continue on else` in the `else` block"); -: 226: } -: 227: } -: 228: else do -: 229: { 20: 230: if var auto ssd = sw.ssd do -: 231: { 4: 232: if var auto se = asStringExp(node.targetMatch) do -: 233: { 2: 234: const auto targetIndex = ssd.getLutIndex(se.value.text()[]); 2: 235: foreach const auto oms in sw.onMatchStatements do 7: 236: foreach const auto ome in oms.onMatchExpressions do -: 237: { 7: 238: if asIntegerExp(ome).value == targetIndex do -: 239: { 1: 240: node.realTarget = oms; 1: 241: return; -: 242: } -: 243: } -: 244: } -: 245: } -: 246: else do -: 247: { 8: 248: scope = scope.pushNested(); 8: 249: if sw.expression?.type do 8: 250: tryAddScopedEnum(node.startPos, sw.expression.type.resolved(), scope); 8: 251: node.targetMatch = expressionSemantic(node.targetMatch, scope); 8: 252: node.targetMatch = implicitConvTo(node.targetMatch, sw.expression.type, scope); 8: 253: scope = scope.pop(); 8: 254: var auto ie = getIntLiteral(node.targetMatch); 8: 255: if ie do -: 256: { 8: 257: foreach const auto oms in sw.onMatchStatements do 32: 258: foreach var auto ome in oms.onMatchExpressions do -: 259: { 32: 260: var auto re = asRangeExp(ome); -: 261: // continue on 32: 262: if !ome.type do -: 263: { 7: 264: scope = scope.pushNested(); 7: 265: ome = expressionSemantic(ome, scope); 7: 266: if re do -: 267: { 2: 268: re.left = implicitConvTo(re.left, sw.expression.type, scope); 2: 269: re.right = implicitConvTo(re.right, sw.expression.type, scope); -: 270: } 5: 271: else do ome = implicitConvTo(ome, sw.expression.type, scope); 7: 272: scope = scope.pop(); -: 273: } 32: 274: var auto e0 = getIntLiteral(re ? re.left else ome); 32: 275: var auto e1 = re ? getIntLiteral(re.right) else null; 32: 276: if e0 && ie.value == e0.value do -: 277: { 6: 278: node.realTarget = oms; 6: 279: return; -: 280: } 26: 281: if e1 && e0 && e0.value <= ie.value && ie.value <= e1.value do -: 282: { 2: 283: node.realTarget = oms; 2: 284: return; -: 285: } -: 286: } -: 287: } -: 288: } -: 289: } 10: 290: node.managedLocals = getParentManagedLocals(node, scope.sym); 10: 291: if !node.realTarget && !node.isElseTargeted do 2: 292: error(scope.filename, node.startPos, "cannot determine the `continue on` target"); 10: 293: } -: 294: -: 295: @override function visitDeclaration(const Declaration* node) -: 296: { -: 297: assert(0); -: 298: } -: 299: -: 300: @override function visitDeclExpression(const DeclExpression* node) -: 301: { -: 302: assert(0); -: 303: } -: 304: -: 305: @override function visitExpressionStatement(ExpressionStatement* node) -: 306: { 11167: 307: scope = scope.pushNested(); 11167: 308: node.expression = expressionSemantic(node.expression, scope); 11167: 309: scope = scope.pop(); 11167: 310: node.flow = Flow.create(FlowKind.isNext); 11167: 311: if !isTypeError(node.expression.type) do -: 312: { 11044: 313: var auto e = stripCast(node.expression); 11044: 314: var auto s = e.symbol; 11044: 315: var auto de = asDeclExp(e); 11044: 316: if e.isLiteral() || s?.kind == $function || de?.expression?.isLiteral() do 3: 317: error(scope.filename, node.startPos, "expression `%s` has no effect", -: 318: format(node.expression).ptr); 11041: 319: else do if e.operator == eopType do 2: 320: error(scope.filename, node.startPos, "type expression `%s` has no effect", -: 321: format(node.expression).ptr); -: 322: } 11167: 323: } -: 324: -: 325: @override function visitForeachStatement(ForeachStatement* node) -: 326: { 589: 327: foreach const auto v in node.variables do -: 328: { 715: 329: declarationSemantic(v, scope); 715: 330: v.flags += VariableFlag.skipManagment; -: 331: } 1178: 332: if var auto e = isReverse(node.expression) do -: 333: { 53: 334: node.isReversed = true; 53: 335: node.expression = e; -: 336: } -: 337: 589: 338: scope = scope.pushNested(); 589: 339: tryAddScopedEnum(node.expression.startPos, node.variables[$-1].type, scope); 589: 340: node.expression = expressionSemantic(node.expression, scope); 589: 341: scope = scope.pop(); -: 342: 589: 343: var auto re = asRangeExp(node.expression); 589: 344: var auto left = re ? re.left else node.expression; 589: 345: var auto right = re?.right; -: 346: -: 347: // foreach const E e in TypeEnum do {} 589: 348: if !right do -: 349: { 347: 350: var auto p = left.startPos; 347: 351: var auto tex = asTypeExp(left); 694: 352: if var auto te = tex ? tex.type.asTypeEnum() else null do -: 353: { 6: 354: var auto ed = te.declaration; 6: 355: if isOrdered in ed.flags do // (E.min):E .. (E.max+1):E -: 356: { 4: 357: var auto ie = (new IntegerExpression).create(p, null, 1, TypeU8.instance()); 4: 358: var auto ae = (new AddExpression).create(p, ed.max, ie); 4: 359: left = (new CastExpression).create(p, ed.min, ed.asTypeDeclared, CastKind.bitCast); 4: 360: right = (new CastExpression).create(p, ae, ed.asTypeDeclared, CastKind.bitCast); 4: 361: node.expression = (new RangeExpression).create(p, left, right, ed.asTypeDeclared); 4: 362: visitForeachStatement(node); 4: 363: return; -: 364: } 2: 365: else do if !ed.base do // __tmp = [E.e0, E.e1, ... , E.elast] -: 366: { 1: 367: var auto ae = (new ArrayExpression).create(p); 1: 368: ae.items.length = ed.members.length; 1: 369: foreach (const auto i; var auto e) in ae.items do 3: 370: e = (new CastExpression).create(p, ed.members[i].value, ed.asTypeDeclared, CastKind.bitCast); -: 371: // sema necessary to create a temp lvalue 1: 372: left = node.expression = expressionSemantic(ae, scope); -: 373: } 1: 374: else do return error(scope.filename, left.startPos, "can only iterate ordered or non-ordered non-derived enum members"); -: 375: } -: 376: } -: 377: // prevent the backend to create an alloca that requires stack push / pop -: 378: // which is not something wanted in e.g double control loops 584: 379: if !right && node.variables.length == 1 do -: 380: { 218: 381: var auto counter = createVariable(node.variables.ptr[0].startPos, Token.generateIdentifier(), TypeUSize(), scope, false); 218: 382: counter.stc += StorageClass.$const; 218: 383: counter.stc -= StorageClass.$var; 218: 384: counter.context = localForeach; 218: 385: node.variables = [counter, node.variables.ptr[0]]; -: 386: } 584: 387: const auto vdCounter = node.variables[0]; 584: 388: vdCounter.flags += isLoopCounter; 584: 389: if vdCounter.isConst() do 579: 390: vdCounter.flags += isImmediate; -: 391: 584: 392: var auto lastVar = node.variables[$-1]; -: 393: var bool hasTypeErrors; -: 394: var bool canIterate; -: 395: // type checks for e0 .. e1 584: 396: if right do -: 397: { 242: 398: if isTypeAuto(lastVar.type) do 78: 399: lastVar.type = left.type; 242: 400: var auto t0 = left.type.resolved(); 242: 401: var auto t1 = right.type.resolved(); 242: 402: if !t0.isIntegral() && !t1.isIntegral() do -: 403: { 2: 404: error(scope.filename, node.startPos, "the range for a `foreach` must give integer indices, not `%s`", format(t0).ptr); 2: 405: hasTypeErrors = true; -: 406: } 242: 407: if node.variables.length != 1 do -: 408: { 1: 409: error(scope.filename, node.startPos, "expected `1` variable for a `foreach` over a range, not `%d`", node.variables.length); 1: 410: hasTypeErrors = true; -: 411: } -: 412: 242: 413: session.startGagging(); 242: 414: var auto t = vdCounter.type.resolved(); 242: 415: var auto cleft = implicitConvTo(left, t, scope); 242: 416: var auto cright = implicitConvTo(right, t, scope); 242: 417: session.stopGagging(); -: 418: 242: 419: if !cleft || !cright do -: 420: { 9: 421: var auto vd = vdCounter; 9: 422: error(scope.filename, node.startPos, "`foreach` variable `%s` must be of type `%s` and not `%s`", -: 423: vd.name.text().ptr, format(right.type).ptr, format(vd.type).ptr); 9: 424: hasTypeErrors = true; -: 425: } -: 426: 242: 427: re.left = cleft; 242: 428: re.right = cright; 242: 429: canIterate = true; 242: 430: if session.foreachBCE && AdditionalCheck.bounds in session.additionalChecks do 4: 431: foreachBCE(node); -: 432: } -: 433: -: 434: // type check for arrays 584: 435: var auto t = left.type; 584: 436: var auto tsa = asTypeStaticArray(t); 584: 437: var auto tsl = asTypeSlice(t); 584: 438: var auto tra = asTypeRcArray(t); 584: 439: if tsa || tsl || tra do -: 440: { 329: 441: if isTypeAuto(lastVar.type) do 572: 442: if var auto tm = left.type.asTypeModified() do 286: 443: lastVar.type = tm.modified.resolved(); 329: 444: canIterate = true; 329: 445: if node.variables.length > 2 do 1: 446: error(scope.filename, node.startPos, "expected 1 or 2 variables for `foreach` over an array, not `%d`", node.variables.length); -: 447: 329: 448: var auto tExpect = t.asTypeModified().modified.resolved(); 329: 449: if isTypeAuto(vdCounter.type) do 101: 450: vdCounter.type = TypeUSize(); 329: 451: var auto vdItem = node.variables.ptr[1]; 329: 452: var auto tItem = vdItem.type.resolved(); 329: 453: var auto tCounter = vdCounter.type.resolved(); -: 454: 329: 455: if tExpect != tItem do -: 456: { 4: 457: error(scope.filename, vdItem.startPos, "`foreach` variable `%s` must be of type `%s` and not `%s`", -: 458: vdItem.name.text().ptr, format(tExpect).ptr, format(tItem).ptr); 4: 459: hasTypeErrors = true; -: 460: } 329: 461: if !vdCounter.isConst() do 1: 462: error(scope.filename, vdCounter.startPos, "`foreach` counter `%s` must be `const`", vdCounter.name.text().ptr); 329: 463: if !tCounter.isIntegral() do -: 464: { 1: 465: error(scope.filename, vdCounter.startPos, "`foreach` counter `%s` must be an integer type", vdCounter.name.text().ptr); 1: 466: hasTypeErrors = true; -: 467: } 329: 468: if tsa do -: 469: { 29: 470: const auto len = tsa.length(); 29: 471: var auto tr = integerTypeFor(len); 29: 472: if tCounter.size < tr.size do 1: 473: error(scope.filename, vdCounter.startPos, "`foreach` counter `%s` over `%s` must be of type `%s` or wider", -: 474: vdCounter.name.text().ptr, format(tsa).ptr, format(tr).ptr); -: 475: } -: 476: else do -: 477: { 300: 478: if tCounter.size < session.ptr_size do 1: 479: error(scope.filename, vdCounter.startPos, "`foreach` counter `%s` over a dynamic array must be of type `usize`", -: 480: vdCounter.name.text().ptr); -: 481: } -: 482: } -: 483: // try foreach over custom types using `.length` and `@operator(a[b])` member func -: 484: else do -: 485: { 255: 486: var auto tp = asTypePointer(node.expression.type); 255: 487: var auto ta = asTypeAggregate(tp ? tp.modified else node.expression.type); 255: 488: if ta do -: 489: { 11: 490: var auto v0 = node.variables.ptr[0]; 11: 491: var auto v1 = node.variables.ptr[1]; 11: 492: var auto oe = node.expression; -: 493: -: 494: // oe is reused, extract the side effect 11: 495: if !symToVarDecl(oe.symbol) do -: 496: { 1: 497: var auto vd = createVariable(oe.startPos, Token.generateIdentifier(), oe.type, scope, true); 1: 498: var auto id = varToIdentExp(vd); 1: 499: vd.initializer = oe; 1: 500: oe = (new DeclExpression).create(oe.startPos, vd, id, oe.type); -: 501: } 11: 502: if asIdentExp(oe) do -: 503: { -: 504: // DotExp sema bug: `e1.e2`, if `e1` is an ident and that sema is already run -: 505: // then the scope wont be set properly to what gave `e1`. -: 506: // Problem only exists if the user type is a TypeAggregate, -: 507: // pointers to TypeAggregate are not affected 10: 508: oe.type = null; 10: 509: oe.symbol = null; -: 510: } -: 511: -: 512: // `0 .. exp.length()` 11: 513: var auto p = node.expression.startPos; 11: 514: var auto z = (new IntegerExpression).create(p, null, 0, TypeUSize()); 11: 515: var auto le = (new IdentExpression).create(p, propLengthToken()); 11: 516: var auto de = (new DotExpression).create(p, oe, le); 11: 517: var auto ce = (new CallExpression).create(p, de); 11: 518: var auto zd = (new RangeExpression).create(p, z, ce); -: 519: 11: 520: node.variables = [v0]; 11: 521: node.expression = zd; -: 522: -: 523: // `foreach const auto c in 0 .. exp.length() do { var auto v = exp[c]; /*previous stmts */ }` 11: 524: var auto bs = node.blockStatement; 11: 525: bs.statements.length += 1; 11: 526: bs.statements[1..$] = bs.statements[0 .. $-1]; 11: 527: var auto ds = (new DeclarationStatement).create(node.blockStatement.startPos); 11: 528: ds.declaration = v1; 11: 529: var auto i = varToIdentExp(v0); 11: 530: var auto ie = (new IndexExpression).create(node.blockStatement.startPos, oe, i); 11: 531: v1.initializer = ie; 11: 532: v1.progress = pending; 11: 533: v1.context = default; 11: 534: bs.statements[0] = ds; -: 535: 11: 536: const auto ec = session.startGagging(); 11: 537: node.skipBlockSema = true; 11: 538: visitForeachStatement(node); 11: 539: node.skipBlockSema = false; 11: 540: canIterate = session.stopGagging() == ec; -: 541: } -: 542: } -: 543: 584: 544: if !canIterate do -: 545: { 6: 546: error(scope.filename, left.startPos, "cannot iterate over `%s` of type `%s`", format(left).ptr, format(left.type).ptr); -: 547: } 578: 548: else do if !hasTypeErrors && !node.skipBlockSema do -: 549: { 557: 550: scope = scope.pushLoop(node); 557: 551: visitStatement(node.blockStatement); 557: 552: scope = scope.pop(); 557: 553: node.flow = node.blockStatement.flow; -: 554: // because the loop body may not be executed at all 557: 555: if node.flow.isReturn() do 2: 556: node.flow = Flow.create(FlowKind.isNext); -: 557: } 584: 558: if session.foreachBCE && AdditionalCheck.bounds in session.additionalChecks do 5: 559: foreachBCE(node); 584: 560: } -: 561: -: 562: @override function visitGotoStatement(GotoStatement* node) -: 563: { 8: 564: assert(!node.symbol); -: 565: // make "use before declared" errors impossible, as allowed for label/goto 8: 566: var auto p = (0xFFFFFF, 0):Position; 8: 567: var auto s = scope.sym.searchWild(node.$label, p, scope.sym); 8: 568: if s?.kind == $label do -: 569: { 7: 570: (*((&s.astNode):LabelDeclaration**)).hasGoto = true; 7: 571: node.symbol = s; -: 572: } 1: 573: else do error(scope.filename, node.startPos, "cannot find matching `label %s`", node.$label.text().ptr); 8: 574: if node.expression do -: 575: { 1: 576: scope = scope.pushNested(); 1: 577: node.expression = expressionSemantic(node.expression, scope); 1: 578: scope = scope.pop(); -: 579: } 8: 580: reachable = node.symbol && node.symbol.astNode.startPos > node.startPos; 8: 581: } -: 582: -: 583: @override function visitIfElseStatement(IfElseStatement* node) -: 584: { 9582: 585: if var auto iv = node.ifVariable do -: 586: { 394: 587: declarationSemantic(iv, scope); 394: 588: scope = scope.pushSym(node.scope.sym); 394: 589: var auto ie = (new IdentExpression).create(node.startPos, iv.name, iv.type); 394: 590: ie.symbol = iv.symbol; 394: 591: node.condition = ie; -: 592: } -: 593: 4791: 594: scope = scope.pushNested(); 4791: 595: node.condition = expressionSemantic(node.condition, scope); 4791: 596: scope = scope.pop(); 9582: 597: if var auto e = toCondition(node.condition, scope) do 4766: 598: node.condition = e; 9582: 599: if var auto e = evaluate(node.condition) do -: 600: { 50: 601: node.condition = e; 50: 602: var BoolExpression* be = asBoolExp(node.condition); 50: 603: node.conditionValue = be.value ? $true else $false; -: 604: // The parent BlockStmt replaces the IfElse with the right block 50: 605: return; -: 606: } -: 607: 4741: 608: reachable = true; 9482: 609: if const auto tb = node.thenBlock do -: 610: { 4741: 611: visitStatement(tb); 4741: 612: node.flow = tb.flow; 4741: 613: if node.ifVariable do 394: 614: scope = scope.pop(); -: 615: } 4741: 616: reachable = node.flow.isContinueToNext(); -: 617: 9482: 618: if const auto eb = node.elseBlock do -: 619: { 687: 620: const auto wasReachable2 = reachable; 687: 621: reachable = true; 687: 622: visitStatement(eb); 687: 623: reachable = wasReachable2 || eb.flow.isContinueToNext(); 687: 624: const auto f1 = node.flow; 687: 625: const auto f2 = eb.flow; 687: 626: if !((f1.isReturn() || f1.isContinue()) && (f2.isReturn() || f2.isContinue())) do -: 627: { 668: 628: node.flow.mixBranch(f2); 1331: 629: if reachable do node.flow.includeNext(); 668: 630: node.flow.pretendLastIsContinueToNext(); -: 631: } -: 632: } -: 633: else do -: 634: { 4054: 635: reachable = true; 4054: 636: node.flow.mixBranch(Flow.create(FlowKind.isNext)); 4054: 637: node.flow.pretendLastIsContinueToNext(); -: 638: } 4741: 639: } -: 640: -: 641: @override function visitOnMatchStatement(OnMatchStatement* node) -: 642: { 1271: 643: foreach var auto e in node.onMatchExpressions do -: 644: { 1466: 645: scope = scope.pushNested(); 1466: 646: e = expressionSemantic(e, scope); 1466: 647: scope = scope.pop(); -: 648: } 1271: 649: if node.blockStatement do -: 650: { 1271: 651: visitStatement(node.blockStatement); 1271: 652: node.flow = node.blockStatement.flow; -: 653: } 1271: 654: } -: 655: -: 656: @override function visitReturnStatement(ReturnStatement* node) -: 657: { 6052: 658: var auto fd = scope.func; 6052: 659: var auto t = fd.returnType.resolved(); 6052: 660: if node.expression do -: 661: { 3283: 662: scope = scope.pushNested(); 3283: 663: tryAddScopedEnum(node.startPos, t, scope); 3283: 664: node.expression = expressionSemantic(node.expression, scope); 3283: 665: scope = scope.pop(); 3283: 666: if node.expression.type:u8* == TypeRange.instance():u8* do 2: 667: error(scope.filename, node.startPos, "cannot return a range"); 3283: 668: if !isTypeAuto(t) do 6404: 669: if var auto newExp = implicitConvTo(node.expression, t, scope) do 3198: 670: node.expression = newExp; -: 671: // check stack local escapes 3283: 672: if fd.isVar() do -: 673: { 19: 674: if !node.expression.isLvalue() do 2: 675: error(scope.filename, node.startPos, "cannot return `%s` because it is a rvalue but `%s` return type is var", format(node.expression).ptr, fd.name.text().ptr); 19: 676: node.isVar = true; 38: 677: if var auto vd = symToVarDecl(node.expression.symbol) do -: 678: { 14: 679: var auto isTSlice = asTypeSlice(vd.type); 14: 680: var auto isPtr = asTypePointer(vd.type); 14: 681: var auto ta = isPtr ? asTypeAggregate(isPtr.modified) else null; 14: 682: const auto isLvParam= vd.context == parameter && vd.isVar(); 14: 683: const auto isLoc = !vd.isStatic() && !vd.isParameter && (vd.symbol.parent.kind == SymbolKind.unamed || vd.symbol.parent.kind == SymbolKind.$function); 14: 684: if !isLvParam && !isTSlice && (isPtr || !ta) && isLoc do 3: 685: error(scope.filename, node.startPos, "return escapes local variable `%s` by reference", vd.name.text().ptr); -: 686: } -: 687: } 6528: 688: else do if var auto vd = symToVarDecl(node.expression.symbol) do -: 689: { -: 690: // use the @return constructor func if a managed aggregate is returned 860: 691: var auto ta = asTypeAggregate(vd.type); 1720: 692: if var auto rct = ta ? ta.declaration.returnCtor else null do -: 693: { 1: 694: var auto p = node.expression.startPos; 1: 695: var auto id1 = (new IdentExpression).create(p, vd.name, vd.type, vd.symbol); 1: 696: var auto id2 = (new IdentExpression).create(p, rct.name, rct.asTypeDeclared, rct.symbol); 1: 697: var auto de = (new DotExpression).create(p, id1, id2); 1: 698: var auto ce = (new CallExpression).create(p, de, null); 1: 699: node.expression = expressionSemantic(ce, scope.pushNested()); -: 700: } -: 701: // if return is a @return rcarray, flag to prevent protective increment 1718: 702: else do if var TypeRcArray* rca = asTypeRcArray(vd.type) do 51: 703: node.skipRcaProtection = vd.getAtReturn(); -: 704: } -: 705: } 2769: 706: else do if !isTypeVoid(t) && !isTypeAuto(t) do 1: 707: error(scope.filename, node.startPos, "expected `return` expression of type `%s`", format(fd.returnType).ptr); 6052: 708: if fd.getAtNoReturn() do 1: 709: error(scope.filename, node.startPos, "cannot `return` in `%s`", format(fd).ptr); 6052: 710: node.managedLocals = getParentManagedLocals(node, scope.sym); 6052: 711: reachable = false; 6052: 712: } -: 713: -: 714: @override function visitSwitchStatement(SwitchStatement* node) -: 715: { 287: 716: scope = scope.pushSwitch(node); 287: 717: scope = scope.pushNested(); 287: 718: node.expression = expressionSemantic(node.expression, scope); 287: 719: scope = scope.pop(); 287: 720: var auto cond = node.expression; -: 721: 287: 722: var auto tsl = asTypeSlice(node.expression.type); 287: 723: var auto tra = asTypeRcArray(node.expression.type); 287: 724: var auto tm = tsl ? tra; 287: 725: if tm && isTypeS8(tm.modified.resolved()) do -: 726: { 22: 727: visitStringSwitchStatement(node); 22: 728: return; -: 729: } -: 730: -: 731: var u64[+] covered; 265: 732: var auto expected = cond.type.resolved(); 265: 733: if !expected.isIntegral() && !isTypeBool(expected) && !asTypeEnumSet(expected) do -: 734: { 3: 735: scope = scope.pop(); 3: 736: return error(scope.filename, cond.startPos, "switch condition `%s` must be an integral type, not `%s`", -: 737: format(cond).ptr, format(expected).ptr); -: 738: } 262: 739: scope = scope.pushNested(); 262: 740: tryAddScopedEnum(cond.startPos, expected, scope); 262: 741: foreach const auto oms in node.onMatchStatements do -: 742: { 1055: 743: visitOnMatchStatement(oms); 1055: 744: reachable = true; 1055: 745: foreach var auto ome in oms.onMatchExpressions do -: 746: { -: 747: var IntegerExpression* e0; -: 748: var IntegerExpression* e1; 2472: 749: if var auto re = asRangeExp(ome) do -: 750: { 91: 751: switchMatchTypeCheck(re.left, expected); 91: 752: switchMatchTypeCheck(re.right, expected); 91: 753: e0 = getIntLiteral(re.left); 91: 754: e1 = getIntLiteral(re.right); -: 755: } -: 756: else do -: 757: { 1145: 758: switchMatchTypeCheck(ome, expected); 1145: 759: e0 = getIntLiteral(ome); -: 760: } 1236: 761: const u64 c0 = e0 ? e0.value else 0; 1236: 762: const u64 c1 = e1 ? e1.value + 1 else e0 ? c0 + 1 else 0; 2467: 763: if e0 && c0 <= c1 do foreach const u64 c in c0 .. c1 do -: 764: { -: 765: label loop1; 40926: 766: foreach const auto cc in covered[] do if cc == c do -: 767: { 4: 768: if e1 do 1: 769: break @loop1, error(scope.filename, ome.startPos, "`%d` is already covered by another on match", c); -: 770: else do 3: 771: break @loop1, error(scope.filename, ome.startPos, "`%s` is already covered by another on match", format(ome).ptr); -: 772: } 2238: 773: covered ~= c; -: 774: } -: 775: } -: 776: } 262: 777: scope = scope.pop(); 262: 778: var auto te = cond.type.asTypeEnum(); -: 779: var TypeEnum* te1; 262: 780: if te do -: 781: { 63: 782: te1 = te; -: 783: var usize numMember; 63: 784: while te do -: 785: { 103: 786: numMember += te.declaration.members.length; 103: 787: te = te.declaration.base?.asTypeEnum(); -: 788: } 63: 789: node.fullCov = covered.length == numMember; -: 790: } 262: 791: if node.elseBlock do -: 792: { 229: 793: scope.flags += isInSwitchElse; 229: 794: visitStatement(node.elseBlock); 229: 795: reachable = true; 229: 796: if node.fullCov do 2: 797: warn(scope.filename, node.elseBlock.startPos, "all `%s` members are covered", te1.declaration.name.text().ptr); -: 798: } 33: 799: else do if !node.fullCov do 18: 800: reachable = true; 262: 801: setSwitchFlow(node); -: 802: 262: 803: scope = scope.pop(); 262: 804: } -: 805: -: 806: function setSwitchFlow(SwitchStatement* node) -: 807: { 279: 808: foreach var auto oms in node.onMatchStatements do 1271: 809: node.flow.mixBranch(oms.flow); 279: 810: if node.elseBlock do 242: 811: node.flow.mixBranch(node.elseBlock.flow); 279: 812: if node.flow.onlyReturns() do -: 813: { 24: 814: node.flow = Flow.create(FlowKind.isReturn); 24: 815: reachable = false; -: 816: } -: 817: // prevent the automatic return if the switch is the last stmt of the func body 255: 818: else do node.flow.pretendLastIsContinueToNext(); 279: 819: } -: 820: -: 821: function visitStringSwitchStatement(SwitchStatement* node) -: 822: { -: 823: import StringSwitchData in styx.string_switch; 22: 824: var auto ssd = node.ssd = new StringSwitchData; -: 825: var usize cnt; 22: 826: foreach var auto oms in node.onMatchStatements do 479: 827: foreach const auto ome in oms.onMatchExpressions do -: 828: { 493: 829: if ome.operator == dotDot do -: 830: { 1: 831: error(scope.filename, ome.startPos, "string matching cannot use ranges"); 1: 832: return; -: 833: } 492: 834: var auto se = asStringExp(ome); 492: 835: if !se do -: 836: { 1: 837: error(scope.filename, ome.startPos, "matches must be string literals"); 1: 838: return; -: 839: } 491: 840: var auto txt = se.value.text(); 491: 841: if !txt.length do -: 842: { 1: 843: error(scope.filename, ome.startPos, "matches must be non-empty string literals"); 1: 844: return; -: 845: } 490: 846: if cnt++ == 255 do -: 847: { 1: 848: error(scope.filename, node.startPos, "only up to 255 matches supported for strings"); 1: 849: return; -: 850: } 489: 851: ssd.appendWord(txt); -: 852: } 18: 853: if !ssd.unique() do -: 854: { 1: 855: error(scope.filename, node.startPos, "matches contain duplicated string(s)"); 1: 856: return; -: 857: } 30: 858: if node.elseBlock do visitStatement(node.elseBlock); -: 859: 17: 860: ssd.prepareLut(); -: 861: 17: 862: var auto lutElType = TypeU8.instance(); -: 863: // `on "string" do` -> `on getLutIndex("string") do` 17: 864: foreach const auto oms in node.onMatchStatements do 216: 865: foreach var auto ome in oms.onMatchExpressions do -: 866: { 230: 867: var auto se = asStringExp(ome); 230: 868: ome = (new IntegerExpression).create(oms.startPos, null, ssd.getLutIndex(se.value.text()), lutElType); -: 869: } 17: 870: foreach var auto oms in node.onMatchStatements do 216: 871: visitOnMatchStatement(oms); -: 872: 17: 873: var auto staScope = scope.sym.parentUnit().scope; 17: 874: var auto p = node.startPos; -: 875: -: 876: // lutVd the computed lookup table as a static array 17: 877: var auto lutLen = (new IntegerExpression).create(p, null, ssd.table.length, TypeUSize()); 17: 878: var auto lutType = (new TypeStaticArray).create(lutElType, lutLen); 17: 879: var auto lutVd = createVariable(p, Token.generateIdentifier(), lutType, staScope, false); 17: 880: var auto lutElExps = (new Expression*[+])(ssd.table.length); 17: 881: foreach (const auto i; var auto e) in lutElExps do 43635: 882: e = (new IntegerExpression).create(p, null, ssd.table[i], lutElType); 17: 883: var auto lutVdInit = (new ArrayExpression).create(p); 17: 884: lutVdInit.items = lutElExps; 17: 885: lutVd.initializer = lutVdInit; 17: 886: var auto lutId = varToIdentExp(lutVd); 17: 887: declarationSemantic(lutVd); -: 888: -: 889: // wtableVd, the word list 17: 890: var auto wordType = (new TypeSlice).create(TypeS8.instance()); 17: 891: var auto wtableLen = (new IntegerExpression).create(p, null, ssd.words.length, TypeUSize()); 17: 892: var auto wtableType = (new TypeStaticArray).create(wordType, wtableLen); 17: 893: var auto wtableVd = createVariable(p, Token.generateIdentifier(), wtableType, staScope, false); 17: 894: var auto wtableExps = (new Expression*[+])(ssd.words.length); 17: 895: foreach (const auto i; var auto w) in ssd.words do 230: 896: wtableExps[i] = (new StringExpression).create(p, identifier(w)); 17: 897: var auto wtableInit = (new ArrayExpression).create(p); 17: 898: wtableInit.items = wtableExps; 17: 899: wtableVd.initializer= wtableInit; 17: 900: var auto wtableId = varToIdentExp(wtableVd); 17: 901: declarationSemantic(wtableVd); -: 902: -: 903: // apply compile time constants to the __sx_ss_lut generic function 17: 904: var auto minCharExp = (new IntegerExpression).create(p, null, ssd.minChar, TypeU8.instance()); 17: 905: var auto maxCharExp = (new IntegerExpression).create(p, null, ssd.maxChar, TypeU8.instance()); 17: 906: var auto numColsExp = (new IntegerExpression).create(p, null, ssd.numCols, TypeU16.instance()); 17: 907: var auto minLenExp = (new IntegerExpression).create(p, null, ssd.minLen, TypeU16.instance()); 17: 908: var auto maxLenExp = (new IntegerExpression).create(p, null, ssd.maxLen, TypeU16.instance()); 17: 909: var auto ssFuncId = (new IdentExpression).create(p, identifier("__sx_ss_lut")); 17: 910: var auto app = (new ApplyExpression).create(p, ssFuncId, [minCharExp:Expression*, maxCharExp, numColsExp, minLenExp, maxLenExp]); -: 911: -: 912: // `switch someString` -> `switch __sx_ss_lut:[minChar, maxChar, numCols, minLen, maxLen](wtableId, someString, lutId.ptr)` 17: 913: var auto rtlCall = (new CallExpression).create(p, app):CallExpression*; 17: 914: var auto lutPtrType = (new TypePointer).create(lutElType); 17: 915: var auto lutPtr = (new PtrExpression).create(lutId, lutPtrType, false); 17: 916: rtlCall.arguments = [wtableId, node.expression, lutPtr]; 17: 917: node.expression = rtlCall; 17: 918: node.expression = expressionSemantic(node.expression, scope); -: 919: 17: 920: if !node.elseBlock do 4: 921: reachable = true; 17: 922: setSwitchFlow(node); 17: 923: } -: 924: -: 925: function switchMatchTypeCheck(var Expression* node; Type* expected) -: 926: { 1327: 927: const auto o = session.startGagging(); 3975: 928: if var auto e = implicitConvTo(node, expected, scope) do node = e; 1327: 929: var auto t = node.type.resolved(); 1327: 930: if session.stopGagging() > o do 6: 931: error(scope.filename, node.startPos, "wrong type for match expression, expected `%s` but got `%s`", format(expected).ptr, format(t).ptr); 1321: 932: else do if !getIntLiteral(node) && node.operator != $bool do 2: 933: error(scope.filename, node.startPos, "match expressions must be integer literals"); 1327: 934: } -: 935: -: 936: @override function visitVersionBlockStatement(VersionBlockStatement* node) -: 937: { 26: 938: if node.thenBlock do -: 939: { 20: 940: visitStatement(node.thenBlock); 20: 941: node.flow = node.thenBlock.flow; -: 942: } 6: 943: else do if node.elseBlock do -: 944: { 4: 945: visitStatement(node.elseBlock); 4: 946: node.flow = node.elseBlock.flow; -: 947: } 26: 948: } -: 949: -: 950: @override function visitWhileStatement(WhileStatement* node) -: 951: { 454: 952: scope = scope.pushLoop(node); 454: 953: scope = scope.pushNested(); 454: 954: node.condition = expressionSemantic(node.condition, scope); 454: 955: scope = scope.pop(); 908: 956: if var auto e = toCondition(node.condition, scope) do 454: 957: node.condition = e; 454: 958: visitStatement(node.blockStatement); 454: 959: scope = scope.pop(); -: 960: 908: 961: if var auto e = evaluate(node.condition) do 370: 962: node.condition = e; -: 963: 454: 964: reachable = true; 454: 965: const auto be = asBoolExp(node.condition); 454: 966: if be && be.value do -: 967: { 368: 968: node.flow = node.blockStatement.flow; 368: 969: reachable = node.flow.containsBreak(); 368: 970: node.flow = reachable ? node.flow.hideReturns() else Flow.create(FlowKind.isReturn); -: 971: } 86: 972: else do node.flow = Flow.create(FlowKind.isNext); 454: 973: } -: 974: -: 975: @override function visitWithStatement(WithStatement* node) -: 976: { 23: 977: scope = scope.pushSym(node.symbol); 23: 978: foreach var auto e in node.expressions do -: 979: { 24: 980: scope = scope.pushNested(); 24: 981: e = expressionSemantic(e, scope); 24: 982: scope = scope.pop(); 24: 983: scope.setSym(node.symbol); 24: 984: var auto et = e.type.resolved(); -: 985: 24: 986: var auto s = et.asSymbol(); 30: 987: if !s do if var auto tp = asTypePointer(et) do 1: 988: s = tp.modified.resolved().asSymbol(); 24: 989: var auto te = asTypeEnum(et); 24: 990: var auto ta = asTypeAggregate(et); 24: 991: var auto tp = asTypePointer(et); 24: 992: ta = tp ? asTypeAggregate(tp.modified) else ta; 24: 993: const auto isUnit = e.symbol && ((e.symbol.kind in unitKinds) || e.symbol.kind == SymbolKind.$import); 24: 994: s = isUnit ? e.symbol else s; 24: 995: if te || ta || isUnit do -: 996: { -: 997: // `with call()` : no temporary is created during CallExp sema because -: 998: // the result is either a lvalue or a rvalue pointer. 46: 999: if var auto ce = asCallExp(e) do -:1000: { 1:1001: var auto vd = createVariable(e.startPos, Token.generateIdentifier(), ce.type.resolved(), scope, false); 1:1002: var auto ae = (new AssignExpression).create(e.startPos, varToIdentExp(vd), e, vd.type); 1:1003: e = (new DeclExpression).create(e.startPos, vd, ae, vd.type, vd.symbol); -:1004: } -:1005: // e.g `with call()` is rewritten `with var V v; v = call()`, -:1006: // put the the Decl + assign in the placeholder for exp with side-effect and takes only `v` 46:1007: if var DeclExpression* de = asDeclExp(e) do 4:1008: if var VariableDeclaration* vd = symToVarDecl(e.symbol) do -:1009: { 2:1010: node.preExpressions ~= e; 2:1011: var auto ie = varToIdentExp(vd); 2:1012: ie.startPos = e.startPos; 2:1013: e = ie; -:1014: } 23:1015: scope.withSyms ~= WithExpression.create(e, s); -:1016: } 1:1017: else do error(scope.filename, e.startPos, -:1018: "expression `%s` does not give a type that is usable as `with` scope", format(e).ptr); -:1019: -:1020: } 23:1021: visitStatement(node.blockStatement); 23:1022: node.flow = node.blockStatement.flow; 23:1023: scope = scope.pop(); 23:1024: } -:1025:} -:1026: -:1027:static function canTupleContentBeManaged(TypeTuple* tt): bool -:1028:{ 97:1029: foreach const auto t in tt.types do -:1030: { 388:1031: if var auto tra = asTypeRcArray(t) do 13:1032: return true; 362:1033: else do if var auto tt2 = asTypeTuple(t) do -:1034: { 22:1035: if canTupleContentBeManaged(tt2) do return true; -:1036: } 326:1037: else do if var auto tsa = asTypeStaticArray(t) do 8:1038: if canStaticArrayContentBeManaged(tsa) do return true; -:1039: } 76:1040: return false; -:1041:} -:1042: -:1043:/// decref rca contained in local static arrays -:1044:static function canStaticArrayContentBeManaged(TypeStaticArray* tsa): bool -:1045:{ 1916:1046: if var auto tra = asTypeRcArray(tsa.modified) do 16:1047: return true; 1884:1048: else do if var auto tt = asTypeTuple(tsa.modified) do -:1049: { 10:1050: if canTupleContentBeManaged(tt) do return true; -:1051: } 1872:1052: else do if var auto ts1 = asTypeStaticArray(tsa.modified) do 47:1053: if canStaticArrayContentBeManaged(ts1) do return true; 936:1054: return false; -:1055:} -:1056: -:1057:/// Get the list of managed locals for a block that's exited normally -:1058:function getBlockManagedLocals(Symbol* s; Position endPos): VariableDeclaration*[+] -:1059:{ -:1060: var VariableDeclaration*[+] result; 45626:1061: if var auto fd = symToFuncDecl(s.parent) do -:1062: { -:1063: // mutable rvalue parameters that are rc arrays -:1064: // 1. are always copied to an alloca (has a .ir, like locals) -:1065: // 2. this alloca store a .dup on func entry (must be decref on exit) 10589:1066: foreach const auto p in fd.parameters do -:1067: { 15060:1068: var auto tra = asTypeRcArray(p.type); 15060:1069: if tra && !p.isVar() && !p.isConst() do 16:1070: result ~= p; -:1071: } -:1072: } 22813:1073: foreach var auto ss in s.children do 156390:1074: if var auto vd = symToVarDecl(ss) do -:1075: { 21602:1076: if vd.startPos <= endPos do 19623:1077: if (VariableFlag.skipManagment !in vd.flags) && !vd.isParameter do -:1078: { 15273:1079: var auto t = vd.type; 15273:1080: var auto ts = asTypeSlice(t); 15273:1081: var auto tr = asTypeRcArray(t); 15273:1082: var auto ta = asTypeAggregate(t); 15273:1083: var auto tt = asTypeTuple(t); 15273:1084: var auto ty = asTypeStaticArray(t); 15273:1085: if ts || tr || ta?.declaration?.defaultDtor || tt?.canTupleContentBeManaged() || ty?.canStaticArrayContentBeManaged() do 2680:1086: result ~= vd; -:1087: } -:1088: } 22813:1089: return result; -:1090:} -:1091: -:1092:/// Get the list of managed locals for a block that's exited using a FlowControl -:1093:function getParentManagedLocals(FlowControl* fc; Symbol* s): VariableDeclaration*[+] -:1094:{ -:1095: var VariableDeclaration*[+] result; 6935:1096: assert(s); -:1097: 6935:1098: const auto fck = fc.kind; 6935:1099: const auto endPos = fc.stopPos; 6935:1100: const auto toFunc = fck == $return; 6935:1101: const auto toLoop = fck == TokenType.$break || fck == TokenType.$continue; 6935:1102: const auto toSwitch = fck == ExtendedTokenType.skBreakOn || fck == ExtendedTokenType.skContinueOn; 6935:1103: assert(toLoop || toFunc || toSwitch); -:1104: 6935:1105: result = getBlockManagedLocals(s, endPos); -:1106: -:1107: var AstNode* n; 6935:1108: while true do -:1109: { 11235:1110: s = s.parent; 11253:1111: if !s || !(n = s.astNode) do return result; 11217:1112: var auto ws = n:WhileStatement*; 11217:1113: var auto fs = n:ForeachStatement*; 11217:1114: var auto fd = n:FunctionDeclaration*; 11217:1115: var auto ss = n:SwitchStatement*; 11217:1116: if toLoop && (ws || fs) do 865:1117: return result; 10352:1118: if toFunc && fd do 6052:1119: return result; 4300:1120: if toSwitch && ss do -:1121: assert(0, "need checks after switches get associated to scopes"); -:1122: 4300:1123: result = getBlockManagedLocals(s, endPos) ~ result; -:1124: } -:1125:} -:1126: -:1127:/** Bound Check Elimination in ForeachStatements. -:1128: given `foreach const auto counter in 0 .. array.length`, -:1129: if `array` is not reassigned and its address not taken (`&array`) -:1130: then bounds checks in `array[counter]` are suppressed */ -:1131:function foreachBCE(ForeachStatement* node) -:1132:{ -:1133: var ForeachBCE fb; 11:1134: fb.entryNode = node; 11:1135: fb.visitForeachStatement(node); 11:1136:} -:1137: -:1138:@final class ForeachBCE: AstVisitor -:1139:{ -:1140: var ForeachStatement* entryNode; -:1141: var Expression* array; -:1142: var VariableDeclaration* counter; -:1143: var u8 pass; -:1144: var bool eliminate; -:1145: -:1146: @override function visitForeachStatement(ForeachStatement* node) -:1147: { 13:1148: if node:u8* == entryNode:u8* do -:1149: { 11:1150: eliminate = true; -:1151: // `foreach const auto i in 0 .. a.length do` 22:1152: if var RangeExpression* re = asRangeExp(node.expression) do -:1153: { 10:1154: var IntegerExpression* ie = getIntLiteral(re.left); 10:1155: var LengthExpression* le = asLengthExp(re.right); 10:1156: if !ie || ie.value != 0 || !le do 4:1157: return; 6:1158: array = le.expression; -:1159: } -:1160: // `foreach (const auto i, var auto v) in a do` 1:1161: else do if node.variables.length == 2 do 1:1162: array = node.expression; 7:1163: if !array do return; -:1164: 7:1165: var auto at = array.type; 7:1166: var auto tsa = asTypeStaticArray(at); 7:1167: var auto tsl = asTypeSlice(at); 7:1168: var auto tra = asTypeRcArray(at); 7:1169: if !tsa && !tsl && !tra do return; 7:1170: counter = node.variables[0]; 7:1171: visitBlockStatement(node.blockStatement); 7:1172: pass++; -:1173: } -:1174: // separate elimination for the nested loop array 2:1175: else do foreachBCE(node); 9:1176: if eliminate do 7:1177: visitBlockStatement(node.blockStatement); 9:1178: } -:1179: -:1180: @override function visitAssignExpression(AssignExpression* node) -:1181: { 3:1182: if pass == 0 do -:1183: { 2:1184: if node.left == array do 1:1185: eliminate = false; -:1186: } 3:1187: node.accept(this); 3:1188: } -:1189: -:1190: @override function visitAtExpression(AtExpression* node) -:1191: { 3:1192: if pass == 0 do -:1193: { 2:1194: if node.expression == array do 1:1195: eliminate = false; -:1196: } 3:1197: node.accept(this); 3:1198: } -:1199: -:1200: @override function visitIndexExpression(IndexExpression* node) -:1201: { 18:1202: node.accept(this); 18:1203: if pass == 0 || !node.sourceLength do 14:1204: return; -:1205: // see expsema, `e0[e1]` is rewritten `e0.ptr[e1]` when `e0` is an array -:1206: // so that IR generator can be more generic 4:1207: var auto p = asPtrExp(node.expression); 4:1208: if !p do return; 4:1209: var auto c = symToVarDecl(node.indexes[0].symbol); 4:1210: if p.expression != array || c:u8* != counter:u8* do 1:1211: return; 3:1212: node.sourceLength = null; 3:1213: if session.vforeachBCE do 3:1214: printf("%s:%d:%d: eliminated bounds check for `%s`\n", entryNode.blockStatement.scope.filename.ptr, node.startPos.line, node.startPos.column, format(node).ptr); 3:1215: } -:1216:} <<<<<< EOF # path=src/styx/semantic/symbolize.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/semantic/symbolize.sx -: 1:unit styx.semantic.symbolize; -: 2: -: 3:@private import -: 4: styx.token, -: 5: styx.scope, -: 6: styx.symbol, -: 7: styx.position, -: 8: styx.session, -: 9: styx.ast.base, -: 10: styx.ast.formatter, -: 11: styx.ast.visitor, -: 12: styx.ast.declarations, -: 13: styx.ast.expressions, -: 14: styx.ast.statements, -: 15: styx.ast.types, -: 16: styx.semantic.evaluate, -: 17: ; -: 18: -: 19:// Associates declarations and statements to symbols and, when necessary, to scopes. -: 20:function symbolizeUnit(UnitDeclaration* node) -: 21:{ 507: 22: var Symbolizer s = Symbolizer.create(node); 507: 23: s.visitConcreteDeclaration(node); 507: 24:} -: 25: -: 26:/// Symbolize a given declaration. -: 27:function symbolizeDeclaration(Declaration* node; Scope* scope) -: 28:{ -: 29: var Symbolizer s; 262: 30: s.scope = scope.pushNested(); 262: 31: s.visitDeclaration(node); 262: 32:} -: 33: -: 34:overload symbolize -: 35:{ -: 36: symbolizeUnit, -: 37: symbolizeDeclaration, -: 38:} -: 39: -: 40:protection (private) -: 41: -: 42:@final class Symbolizer : AstVisitor -: 43:{ -: 44: var Scope* scope; -: 45: var UnitDeclaration* $unit; -: 46: -: 47: function checkUniqueName(AstNode* node; Token* name; SymbolKind kind) -: 48: { 31024: 49: var auto fd = kind == $function ? *((&node):FunctionDeclaration**) else null; 31024: 50: const auto funcIsType = fd && FunctionFlag.isType in fd.flags; 31024: 51: var Symbol* s = scope.sym.find(name); -: 52: 31024: 53: if s && s.parent == scope.sym do -: 54: { 12: 55: if !funcIsType && // TypeFunction.declaration.name is meaningless 11: 56: !(kind == $import && s.kind == $import) do // allow `import a.a1, a.a2` -: 57: { 10: 58: error($unit.filename, node.startPos, "symbol `%s` already declared line %d", name.text().ptr, s.astNode.startPos.line); -: 59: } -: 60: } 31012: 61: else do if scope.sym.kind == unamed && scope.sym.parent.kind == unamed do -: 62: { 5636: 63: s = scope.sym; 5636: 64: scope.setSym(s.parent); 5636: 65: checkUniqueName(node, name, kind); 5636: 66: scope.setSym(s); -: 67: } 25376: 68: else do if scope.func do -: 69: { 16161: 70: s = scope.func.symbol.find(name); 16161: 71: if s && !funcIsType do 2: 72: error($unit.filename, node.startPos, "symbol `%s` shadows a parameter", name.text().ptr); -: 73: } 31024: 74: } -: 75: -: 76: function createDeclarationSymbol(Declaration* node; SymbolKind kind; bool isAggregate = false) -: 77: { 19688: 78: const bool needScope = kind in needScopeKinds; 19688: 79: checkUniqueName(node, node.name, kind); 19688: 80: var auto ad = isAggregate ? *((&node):AggregateDeclaration**) else null; 19688: 81: var auto sym = (new Symbol).create(node.name, scope.sym, kind); 19688: 82: sym.astNode = node; 19688: 83: node.symbol = sym; 19688: 84: if needScope do -: 85: { 1500: 86: scope = ad ? scope.pushAggregate(ad) else scope.pushSym(sym); 1500: 87: node.scope = scope; 1500: 88: propagateIsInGeneric(node); -: 89: } 19688: 90: node.accept(this); 19688: 91: if needScope do 1500: 92: scope = scope.pop(); 19688: 93: } -: 94: -: 95: @constructor function create(UnitDeclaration* node) -: 96: { 507: 97: $unit = node; 507: 98: } -: 99: -:100: function propagateIsInGeneric(Declaration* node) -:101: { 7099:102: if node.isGeneric() do 185:103: node.scope.flags += isInGeneric; 7099:104: } -:105: -:106: @override function visitAliasDeclaration(AliasDeclaration* node) -:107: { 361:108: createDeclarationSymbol(node, SymbolKind.$alias); 361:109: node.scope = scope; 361:110: } -:111: -:112: @override function visitBlockStatement(BlockStatement* node) -:113: { 13721:114: if node.noScope do -:115: { 26:116: node.accept(this); 26:117: return; -:118: } 13695:119: var auto sym = (new Symbol).createUnamed(scope.sym); 13695:120: sym.astNode = node; 13695:121: node.symbol = sym; 13695:122: scope = scope.pushSym(sym, true); 13695:123: node.scope = scope; 13695:124: node.accept(this); 13695:125: scope = scope.pop(); 13695:126: } -:127: -:128: @override function visitClassDeclaration(ClassDeclaration* node) -:129: { 494:130: node.asTypeDeclared = (new TypeClass).create(node); 494:131: if node.body do -:132: { -:133: // note: type is set later to a pointer to a static array 493:134: node.vtableVar = (new VariableDeclaration).create(node.body.startPos, vtableToken()); 493:135: node.vtableVar.stc = [$var]; -:136: } 494:137: createDeclarationSymbol(node, SymbolKind.$class, true); 494:138: node.symbol.type = node.asTypeDeclared; 494:139: } -:140: -:141: @override function visitDeclaration(Declaration* node) -:142: { 16208:143: $unit ?= scope.sym.parentUnit(); 16208:144: node.isHeader = $unit.isHeader; 16208:145: super(node); 16208:146: } -:147: -:148: @override function visitEnumDeclaration(EnumDeclaration* node) -:149: { 440:150: createDeclarationSymbol(node, SymbolKind.$enum); 440:151: node.symbol.type = (new TypeEnum).create(node); 440:152: node.asTypeDeclared = node.symbol.type; 440:153: node.scope = scope; 440:154: } -:155: -:156: @override function visitEnumMember(EnumMember* node) -:157: { 1010:158: createDeclarationSymbol(node, SymbolKind.enumMember); 1010:159: } -:160: -:161: @override function visitExpressionAlias(ExpressionAlias* node) -:162: { 18:163: createDeclarationSymbol(node, SymbolKind.expAlias); 18:164: node.scope = scope; 18:165: } -:166: -:167: @override function visitForeachStatement(ForeachStatement* node) -:168: { 642:169: var auto sym = (new Symbol).createUnamed(scope.sym); 642:170: sym.astNode = node; 642:171: node.symbol = sym; 642:172: scope = scope.pushLoop(node); 642:173: node.scope = scope; 642:174: node.accept(this); 642:175: scope = scope.pop(); 642:176: } -:177: -:178: @override function visitFunctionDeclaration(FunctionDeclaration* node) -:179: { 5602:180: const auto entrySc = scope; -:181: var Declaration* outerParentAggr; -:182: -:183: // append outer member func to the aggregate AST 5602:184: if node.externalAggregate do -:185: { 9:186: var auto s = $unit.symbol.find(node.externalAggregate); 9:187: if !s do -:188: { 1:189: error(scope.filename, node.startPos, "cannot locate or forward reference to unit-local aggregate `%s`", node.externalAggregate.text().ptr); 1:190: return; -:191: } 8:192: if s.kind !in aggregateKinds do -:193: { 1:194: error(scope.filename, node.startPos, "outer member function must be for a class, struct or union, not `%s`", format(s.astNode).ptr); 1:195: return; -:196: } 7:197: if scope.sym.kind !in unitKinds do -:198: { 1:199: error(scope.filename, node.startPos, "outer member function must be declared in the same scope as `%s`", format(s.astNode).ptr); 1:200: return; -:201: } 6:202: outerParentAggr = s.astNode.asDeclaration(); 6:203: var auto a = outerParentAggr:AggregateDeclaration*; 6:204: a.body.items ~= node; 6:205: scope = outerParentAggr.scope; -:206: } -:207: -:208: // function types can omit the name but also use FunctionDeclaration as descriptor. 5599:209: if node.name do 5471:210: checkUniqueName(node, node.name, SymbolKind.$function); -:211: 5599:212: var auto sym= (new Symbol).create(node.name, scope.sym, SymbolKind.$function); 5599:213: sym.astNode = node; 5599:214: node.symbol = sym; 5599:215: scope = scope.pushFunc(node); 5599:216: node.scope = scope; 5599:217: propagateIsInGeneric(node); 5599:218: if outerParentAggr && outerParentAggr.isGeneric() do 1:219: node.scope.flags += isInGeneric; -:220: 5599:221: node.symbol.type = (new TypeFunction).create(node, false); 5599:222: node.asTypeDeclared = node.symbol.type; -:223: -:224: // e.g an AliasDecl located in an aggregate 5599:225: const bool isForType = FunctionFlag.isType in node.flags; 5599:226: const bool hasThisAlready = node.parameters.length && node.parameters[0].name == thisToken(); -:227: 5599:228: if (sym.parent.kind in unitKinds) && !isForType && !hasThisAlready do 2908:229: node.stc += $static; -:230: 5599:231: if node.returnType do 5599:232: visitConcreteType(node.returnType); -:233: -:234: // add the hidden `this` to `@constructor`; `@destructor` and other member functions 5599:235: if !hasThisAlready && !isForType && sym.parent.kind in aggregateKinds && !node.isStatic() && !node.getAtForeign() do -:236: { 4016:237: if var auto t = sym.parentAggregate() do -:238: { 2008:239: var auto tid = (new TypeIdentifier).create(t.name); 2008:240: tid.startPos = node.startPos; 2008:241: tid.solved = (*(&t.astNode):Declaration**).asTypeDeclared; 2008:242: var auto tp = (new TypePointer).create(tid); 2008:243: tid.progress = tp.progress = done; 2008:244: var auto vd = (new VariableDeclaration).create(node.startPos, thisToken(), tp); 2008:245: vd.context = VariableDeclarationContext.parameter; 2008:246: node.parameters = vd ~ node.parameters; 2008:247: vd.flags += implicitThis; -:248: } -:249: } 5840:250: if node.genericParameters do visitGenericParameters(node.genericParameters); 13543:251: foreach var auto p in node.parameters do visitVariableDeclaration(p); 10377:252: if node.body do visitStatement(node.body); -:253: 5599:254: scope = scope.pop(); -:255: 11198:256: if var auto atOverload = node.getAtOverload() do -:257: { 18:258: if var auto ie = asIdentExp(atOverload.arguments[0]) do -:259: { -:260: var OverloadDeclaration* od; 8:261: var auto p = node.symbol.parent; 16:262: if var auto o = p.find(ie.identifier) do -:263: { 4:264: if !(od = symToOverDecl(o)) do 1:265: error(scope.filename, node.startPos, "cannot create overload `%s` because the name is already used to declare `%s`", ie.identifier.text().ptr, format(o.astNode).ptr); -:266: } 4:267: else do visitOverloadDeclaration(od = (new OverloadDeclaration).create(p.astNode.startPos, ie.identifier)); 8:268: if od do 7:269: od.members ~= (new IdentExpression).create(node.name.position, node.name); -:270: } 1:271: else do error(scope.filename, atOverload.startPos, "`@overload` parameter must be an identifier"); -:272: } -:273: 5599:274: scope = entrySc; 5599:275: } -:276: -:277: @override function visitGenericParameter(GenericParameter* node) -:278: { 793:279: createDeclarationSymbol(node, SymbolKind.genericParameter); 793:280: } -:281: -:282: @override function visitIfElseStatement(IfElseStatement* node) -:283: { 5163:284: if node.ifVariable do -:285: { 400:286: var auto sym = (new Symbol).createUnamed(scope.sym); 400:287: scope = scope.pushSym(sym); 400:288: sym.astNode = node; 400:289: node.scope = scope; 400:290: visitVariableDeclaration(node.ifVariable); 400:291: visitBlockStatement(node.thenBlock); 400:292: scope = scope.pop(); 504:293: if node.elseBlock do visitBlockStatement(node.elseBlock); -:294: } 4763:295: else do node.accept(this); 5163:296: } -:297: -:298: @override function visitImportDeclaration(ImportDeclaration* node) -:299: { 202:300: assert(scope.sym.kind != $function); -:301: // in function bodies, since forward decls are not supported, create a scope. 202:302: if scope.sym.kind == unamed do -:303: { 25:304: node.symbol = (new Symbol).createUnamed(scope.sym); -:305: } 202:306: const usize first = node.isSelective ? node.importList.length - 1 else 0; 202:307: foreach const auto tid in node.importList[first .. $] do -:308: { 441:309: if scope.sym.find(tid.identifier, SymbolKind.$import) do 226:310: continue; 215:311: checkUniqueName(tid, tid.identifier, SymbolKind.$import); 215:312: var auto s = (new ImportElement).create(tid.identifier, scope.sym, null); 215:313: s.astNode = tid; -:314: } 202:315: if scope.func && first do 12:316: foreach const auto tid in node.importList[0 .. first] do -:317: { 14:318: checkUniqueName(tid, tid.identifier, SymbolKind.$import); -:319: } 202:320: } -:321: -:322: @override function visitLabelDeclaration(LabelDeclaration* node) -:323: { 15:324: if scope.func do 14:325: createDeclarationSymbol(node, SymbolKind.$label); -:326: else do 1:327: error(scope.filename, node.startPos, "labels can only be declared in function bodies"); 15:328: } -:329: -:330: @override function visitOverloadDeclaration(OverloadDeclaration* node) -:331: { 52:332: node.symbol = (new Symbol).create(node.name, scope.sym, SymbolKind.$overload); 52:333: node.symbol.astNode = node; 52:334: node.scope = scope.pushNested(); 52:335: node.symbol.type = (new TypeOverload).create(node); 52:336: node.asTypeDeclared = node.symbol.type; 52:337: foreach var auto m in node.members do 103:338: visitConcreteExpression(m); 52:339: } -:340: -:341: @override function visitStructDeclaration(StructDeclaration* node) -:342: { 538:343: node.asTypeDeclared = (new TypeStruct).create(node); 538:344: createDeclarationSymbol(node, SymbolKind.$struct, true); 538:345: node.symbol.type = node.asTypeDeclared; 538:346: } -:347: -:348: @override function visitTypeFunction(TypeFunction* node) -:349: { 130:350: node.declaration.flags += isType; 130:351: node.accept(this); 130:352: } -:353: -:354: @override function visitUnionDeclaration(UnionDeclaration* node) -:355: { 28:356: node.asTypeDeclared = (new TypeUnion).create(node); 28:357: createDeclarationSymbol(node, SymbolKind.$union, true); 28:358: node.symbol.type = node.asTypeDeclared; 28:359: } -:360: -:361: @override function visitUnitDeclaration(UnitDeclaration* node) -:362: { 507:363: var auto sym = Root.instance(); 507:364: assert(node.identifiers.kind == id); -:365: 507:366: var auto tid = node.identifiers; 507:367: var Token*[+] chain = tid.chain(); 507:368: const usize lastIndex = chain.length - 1; -:369: 507:370: if session.hasRtl && tid.identifier.iptr() != rtlToken().iptr() do -:371: { 78:372: var auto p = (node.startPos.line + 1, 0):Position; 78:373: var auto id = (new ImportDeclaration).create(p); 78:374: id.importList ~= (new TypeIdentifier).create(rtlToken()); 78:375: id.$protection = private; 78:376: node.declarations.items = id ~ node.declarations.items; -:377: } -:378: 507:379: if session.cover do -:380: { -:381: // add var s32[numLines] __coverageData; 10:382: var auto numLines = node.stopPos.line; 10:383: var auto lengthExp = (new IntegerExpression).create(node.startPos, null, numLines, TypeU32.instance()); 10:384: var auto tsa = (new TypeStaticArray).create(TypeU32.instance(), lengthExp); 10:385: var auto coverArray = (new VariableDeclaration).create(node.startPos, identifier("__coverageData"), tsa); 10:386: coverArray.progress = done; 10:387: node.coverData = coverArray; 10:388: node.declarations.items ~= coverArray; -:389: } -:390: 507:391: foreach (const auto i; const auto ci) in chain do -:392: { 596:393: var auto c = sym.find(ci, unitKinds); 596:394: const bool isLast = i == lastIndex; -:395: -:396: // either already symbolized or create a "fake unit symbol" to permit qualified lookups 596:397: if !isLast do 89:398: continue sym = c ? (new Symbol).create(ci, sym, SymbolKind.unitDot); -:399: 507:400: if c do -:401: { -:402: // already exists 3:403: if c.kind == SymbolKind.$unit do 1:404: break error(node.filename, node.startPos, "a unit named `%s` is already parsed", tokenChainText(chain).ptr); -:405: // replace a "fake unit symbol" by the real unit. -:406: // This happens for example if "a.b.sx" is symbolized before "a.sx". 2:407: if c.kind == unitDot do -:408: { 2:409: sym = c; 2:410: sym.kind = SymbolKind.$unit; 2:411: sym.astNode = node; 2:412: node.symbol = sym; 2:413: scope = (new Scope).create(sym, node.filename); 2:414: node.scope = scope; 2:415: node.accept(this); -:416: } -:417: else do assert(0); -:418: } -:419: // create real unit at the end of the chain -:420: else do -:421: { 504:422: sym = (new Symbol).create(ci, sym, SymbolKind.$unit); 504:423: sym.astNode = node; 504:424: node.symbol = sym; 504:425: scope = (new Scope).create(sym, node.filename); 504:426: node.scope = scope; 504:427: node.accept(this); -:428: } -:429: } -:430: -:431: // for fully qualified searches in the current module 507:432: while tid do -:433: { 596:434: var auto ie= (new ImportElement).create(tid.identifier, sym, null, true); 596:435: sym = ie; 596:436: ie.astNode = tid; 596:437: tid = tid.next; 1103:438: if !tid do ie.terminalUnit = node.symbol; -:439: } 507:440: } -:441: -:442: @override function visitVariableDeclaration(VariableDeclaration* node) -:443: { 15992:444: var auto rightScope = scope; 15992:445: createDeclarationSymbol(node, SymbolKind.variable); 15992:446: node.scope = rightScope.pushNested(); 15992:447: if node.symbol.parent.kind in unitKinds do 215:448: node.stc += $static; 15992:449: } -:450: -:451: @override function visitVersionBlockDeclaration(VersionBlockDeclaration* node) -:452: { 87:453: var auto e = evaluate(node.versionExpression).asBoolExp(); 87:454: node.isTrue = e.value:bool; 87:455: e.free(); 87:456: if node.isTrue do -:457: { 69:458: if node.elseDeclarations do 50:459: node.elseDeclarations.free(); 69:460: node.elseDeclarations = null; 69:461: if node.thenDeclarations do 69:462: visitDeclarations(node.thenDeclarations); -:463: } -:464: else do -:465: { 18:466: if node.thenDeclarations do 17:467: node.thenDeclarations.free(); 18:468: node.thenDeclarations = null; 18:469: if node.elseDeclarations do 4:470: visitDeclarations(node.elseDeclarations); -:471: } 87:472: } -:473: -:474: @override function visitVersionBlockStatement(VersionBlockStatement* node) -:475: { 28:476: var auto e = evaluate(node.versionExpression).asBoolExp(); 28:477: node.isTrue = e.value:bool; 28:478: e.free(); 28:479: if node.isTrue do -:480: { 21:481: if node.elseBlock do 12:482: node.elseBlock.free(); 21:483: node.elseBlock = null; 21:484: if node.thenBlock do 21:485: visitBlockStatement(node.thenBlock); -:486: } -:487: else do -:488: { 7:489: if node.thenBlock do 6:490: node.thenBlock.free(); 7:491: node.thenBlock = null; 7:492: if node.elseBlock do 5:493: visitBlockStatement(node.elseBlock); -:494: } 28:495: } -:496: -:497: @override function visitWhileStatement(WhileStatement* node) -:498: { 474:499: var auto sym = (new Symbol).createUnamed(scope.sym); 474:500: sym.astNode = node; 474:501: node.symbol = sym; 474:502: scope = scope.pushLoop(node); 474:503: node.scope = scope; 474:504: node.accept(this); 474:505: scope = scope.pop(); 474:506: } -:507: -:508: @override function visitWithStatement(WithStatement* node) -:509: { 24:510: var auto sym = (new Symbol).createUnamed(scope.sym); 24:511: sym.astNode = node; 24:512: node.symbol = sym; 24:513: scope = scope.pushSym(sym); 24:514: node.scope = scope; 24:515: if node.blockStatement do 24:516: visitBlockStatement(node.blockStatement); 24:517: scope = scope.pop(); 24:518: } -:519:} -:520: -:521:version unittest do -:522:{ -:523: import styx.lexer; -:524: import styx.parser; -:525: import system; -:526:} -:527: -:528:@unittest function testSelfSymbolize() -:529:{ -:530: //var Lexer* lx = (new Lexer).createFromText(echo(filename).fileRead(), echo(filename), 1, 0); -:531: var Lexer* lx = (new Lexer).createFromFile(echo(filename), true); -:532: -:533: var Parser* p = (new Parser).create(lx, false); -:534: var UnitDeclaration* u = p.parseUnitDeclaration(); -:535: assert(u); -:536: -:537: symbolizeUnit(u); -:538: -:539: delete p; -:540: delete lx; -:541: Root.reset(); -:542:} -:543: -:544:@unittest function testError() -:545:{ -:546: const s32 line = (echo(line) + 1):s32; -:547: const s8[] txt = ` -:548: unit u; -:549: var s32 a; -:550: var s64 a; -:551: struct Foo -:552: { -:553: var u64 b; -:554: var TypeIdent b; -:555: } -:556: `; -:557: var Lexer* lx = (new Lexer).createFromText(txt, echo(filename), line, 0, true); -:558: var Parser* p = (new Parser).create(lx, false); -:559: var UnitDeclaration* u = p.parseUnitDeclaration(); -:560: assert(u); -:561: -:562: symbolizeUnit(u); -:563: -:564: delete p; -:565: delete lx; -:566: Root.reset(); -:567:} <<<<<< EOF # path=src/styx/semantic/types.gcov -: 0:Source:/builds/styx-lang/styx/src/styx/semantic/types.sx -: 1:unit styx.semantic.types; -: 2: -: 3:@private import -: 4: styx.ast.base, -: 5: styx.ast.declarations, -: 6: styx.ast.expressions, -: 7: styx.ast.formatter, -: 8: styx.ast.types, -: 9: styx.ast.visitor, -: 10: styx.semantic.declarations, -: 11: styx.semantic.deprecations, -: 12: styx.semantic.evaluate, -: 13: styx.semantic.expressions, -: 14: styx.semantic.memulator, -: 15: styx.scope, -: 16: styx.session, -: 17: styx.symbol, -: 18: styx.token, -: 19: ; -: 20: -: 21:/** -: 22: * Resolve the type described by a `Type` and returns -: 23: * the matching concrete `Type`. -: 24: * -: 25: * Params: -: 26: * node = The type to solve. -: 27: * scope = The scope where the type is declared. -: 28: */ -: 29:function resolveType(Type* node; Scope* scope): Type* -: 30:{ 40252: 31: if node.progress == done do 18532: 32: return node; 21720: 33: else do if node.progress == running do -: 34: { -: 35: /*var AstNode* loc = scope.sym.astNode; -: 36: session.error(scope.filename, loc.startPos, "circular reference to type `%s`", format(node).ptr); -: 37: return node;*/ -: 38: assert(0, "resolveType() cycle"); -: 39: } 21720: 40: var auto tr = TypeResolver.create(scope); 21720: 41: tr.visitConcreteType(node); 21720: 42: node.progress = done; 21720: 43: node = tr.result ? node; 21720: 44: return node; -: 45:} -: 46: -: 47:protection (private) -: 48: -: 49:@final class TypeResolver : AstVisitor -: 50:{ -: 51: var bool isFirstTid; -: 52: var TypeIdentifier* firstTid; -: 53: var Scope* scope; -: 54: var Symbol* useSite; -: 55: var Type* result; -: 56: var bool mustRunDeclSema; -: 57: var bool preventDeclSema; -: 58: -: 59: @constructor function create(Scope* scope) -: 60: { 21720: 61: this.scope = scope; 21720: 62: this.isFirstTid = true; 21720: 63: this.useSite = scope.sym; -: 64: // while processing exp (in a body, in an init) and unless blocked, -: 65: // start declSema for types that give a decl. there's an exception for classes. 21720: 66: preventDeclSema = ScopeFlag.doSkipAdhocSema in scope.flags; 21720: 67: mustRunDeclSema = !preventDeclSema && (scope.func || (ScopeFlag.isInInitializer in scope.flags)); 21720: 68: } -: 69: -: 70: function tryDeclSema(Type* t; Symbol* s) -: 71: { 5268: 72: switch t.kind do -: 73: { -: 74: // classes: declsema of ancestors is required early, to check the vtable. -: 75: // "preventDeclSema" can be used to maintain a sane analysis path and when -: 76: // the type of a member function parameter is checked. -: 77: on TokenType.$class, -: 78: // other decl kinds: things discovered in -I path or not yet analyzed -: 79: // repro: invert order llvm.sx and irgen.sx re passed to the compiler -: 80: TokenType.$union, TokenType.$struct, TokenType.$enum do -: 81: { 5244: 82: if !preventDeclSema do 2798: 83: mustRunDeclSema = true; -: 84: } 24: 85: else do {} -: 86: } -: 87: // note if there are more problems with that then that means that -: 88: // bodySemantic should be called in a separate loop that declarationSemantic 5268: 89: var auto d = s.astNode.asDeclaration(); 5268: 90: if mustRunDeclSema && d && d.progress == SemanticProgress.pending do 141: 91: declarationSemantic(d, d.scope); 5268: 92: } -: 93: -: 94: @override function visitTypeAppliedGeneric(TypeAppliedGeneric* node) -: 95: { 43: 96: scope.flags += isInInitializer; 43: 97: node.applyExpression = expressionSemantic(node.applyExpression, scope); 43: 98: scope.flags -= isInInitializer; 43: 99: var auto t = node.applyExpression.type.resolved(); 86:100: if var auto ds = t.asSymbol() do 42:101: tryDeclSema(t, ds); 43:102: result = t; 43:103: } -:104: -:105: @override function visitTypeEcho(TypeEcho* node) -:106: { 18:107: var auto ee = asEchoExp(node.expression); 18:108: const auto i = ee.command.iptr(); 18:109: if i != echoTypeToken().iptr() && 7:110: i != echoFunctToken().iptr() && 6:111: i != echoGetPointedTypeToken().iptr() && 5:112: !ee.command.isTok:[$return]() do -:113: { 1:114: error(scope.filename, ee.startPos, "the echo command `%s` does not yield a type", ee.command.text().ptr); 1:115: result = TypeError.instance(); 1:116: return; -:117: } 17:118: node.expression = expressionSemantic(node.expression, scope); 17:119: result = node.expression.type; 17:120: } -:121: -:122: @override function visitTypeElements(TypeElements* node) -:123: { 19:124: node.elements = resolveType(node.elements, scope); 19:125: var auto tt1 = asTypeTuple(node.elements); 19:126: if !tt1 do -:127: { 1:128: error(scope.filename, node.indexes[0].startPos, "`%s` does not represent a type tuple", format(node).ptr); 1:129: result = TypeError.instance(); 1:130: return; -:131: } -:132: -:133: function getAndCheckIndexValue(Expression* e): IntegerExpression* -:134: { 39:135: var auto result = getIntLiteral(e); 39:136: if !result do -:137: { 4:138: error(scope.filename, e.startPos, "`%s` does not give an integer literal", format(e).ptr); -:139: } -:140: else do -:141: { 35:142: const auto v = result.value; 35:143: if v > tt1.types.length do -:144: { 4:145: result = null; 4:146: error(scope.filename, e.startPos, "`%d` is greater than the count of types `%d`", v, tt1.types.length); -:147: } -:148: } 39:149: return result; -:150: } -:151: 18:152: var auto tt2 = (new TypeTuple).create([]); 18:153: foreach var auto i in node.indexes do -:154: { 25:155: var auto re = asRangeExp(i); 25:156: var auto de = i.operator == dollar || (re && (re.left.operator == dollar || re.right.operator == dollar)); 25:157: if de do -:158: { 1:159: var auto ie = (new IntegerExpression).create(node.startPos, null, tt1.types.length, TypeU32.instance()); 1:160: scope = scope.pushDollar(ie); -:161: } 25:162: i = expressionSemantic(i, scope); 50:163: if var auto e = evaluate(i) do 10:164: i = e; 26:165: if de do scope = scope.pop(); 25:166: if re do -:167: { 14:168: var auto i0 = getAndCheckIndexValue(re.left); 14:169: var auto i1 = getAndCheckIndexValue(re.right); 14:170: if !i0 || !i1 do -:171: { 3:172: result = TypeError.instance(); 3:173: return; -:174: } 11:175: const auto d = i1.value - i0.value; 11:176: const auto o = tt2.types.length; 11:177: tt2.types.length += d; 11:178: tt2.types[o .. d] = tt1.types[i0.value .. i1.value]; -:179: } -:180: else do -:181: { 22:182: if var auto i0 = getAndCheckIndexValue(i) do 8:183: tt2.types ~= tt1.types[i0.value]; -:184: else do -:185: { 3:186: result = TypeError.instance(); 3:187: return; -:188: } -:189: } -:190: } 12:191: memulateTypeTuple(tt2, scope); 12:192: result = tt2; 12:193: result.progress = done; 12:194: } -:195: -:196: @override function visitTypeEnum(TypeEnum* node) -:197: { 1:198: result = node.declaration.type; 1:199: } -:200: -:201: @override function visitTypeEnumSet(TypeEnumSet* node) -:202: { -:203: //do not replace .modified with the enum base integral type 26:204: } -:205: -:206: @override function visitTypeFunction(TypeFunction* node) -:207: { 5444:208: if node.declaration.progress == SemanticProgress.pending do 124:209: declarationSemantic(node.declaration, scope); -:210: var bool error; 5444:211: foreach var auto p in node.declaration.parameters do -:212: { 7588:213: if isTypeError(p.type) do 5:214: break error = true; -:215: } 5444:216: if isTypeError(node.declaration.returnType) do 2:217: error = true; 5444:218: if error do -:219: { 7:220: node.free(); 7:221: result = TypeError.instance(); -:222: } 5444:223: node.declaration.asTypeDeclared = node; 5444:224: } -:225: -:226: @override function visitTypeIdentifier(TypeIdentifier* node) -:227: { -:228: var Symbol* s; -:229: var Type* t; -:230: 5595:231: if isFirstTid do -:232: { 5551:233: firstTid = node; -:234: } -:235: // apply generic 5595:236: if node.genericArguments do -:237: { 43:238: isFirstTid = false; 43:239: var auto id = (new IdentExpression).create(node.startPos, node.identifier); 43:240: var auto ae = (new ApplyExpression).create(node.startPos, id, node.genericArguments); 43:241: var auto tg = (new TypeAppliedGeneric).create(ae); 43:242: visitTypeAppliedGeneric(tg); 43:243: s = scope.sym; 43:244: if !node.next do 41:245: return; -:246: } -:247: // solve + solve result alias -:248: else do -:249: { 5552:250: if isFirstTid do -:251: { 5510:252: isFirstTid = false; 5510:253: foreach var auto we in scope.withSyms do -:254: { 11:255: if (s = we.searchSym.searchStrict(node.identifier, node.startPos, useSite)) do 1:256: break; -:257: } 5510:258: s ?= scope.sym.searchWild(node.identifier, node.startPos, useSite); -:259: } -:260: else do -:261: { 42:262: s = scope.sym.searchStrict(node.identifier, node.startPos, useSite); -:263: } -:264: } 11108:265: if var auto ad = symToAliasDecl(s) do -:266: { 178:267: checkDeprecated(node, ad, scope); 178:268: getAliasee(ad, scope, t, s); -:269: } -:270: -:271: // set the flag for `SomeTypeTuple.expand` 5554:272: if t:u8* && node.next && !node.next.next && node.next.identifier.iptr() == propExpandToken().iptr() do -:273: { 4:274: if var auto tt0 = asTypeTuple(t) do -:275: { 1:276: t = (new TypeTuple).create(tt0.types, true); 1:277: node.next = null; -:278: } -:279: } -:280: -:281: // chain end 5554:282: if !node.next || (!s && !t) do -:283: { -:284: // alias that gave a Type 5510:285: if t do -:286: { 310:287: if var auto ds = t.asSymbol() do -:288: { 26:289: checkDeprecated(node, ds.astNode, scope); 26:290: tryDeclSema(t, ds); -:291: } 155:292: node.solved = t; 155:293: return; -:294: } -:295: // symbol that is a decl which give a TypeDeclared 5355:296: else do if s && (t = s.asType()) do -:297: { 5200:298: tryDeclSema(t, s); 5200:299: checkDeprecated(node, s.astNode, scope); 5200:300: node.solved = t; 5200:301: return; -:302: } 310:303: else do if var auto gp = symToGenericParam(s) do -:304: { 242:305: if var auto tt = gp.appliedType do -:306: { 121:307: node.solved = tt; 121:308: return; -:309: } -:310: } -:311: // error 34:312: result = TypeError.instance(); 34:313: var auto args = s ? ("`%s` is used as a type", format(s.astNode).ptr) 29:314: else ("cannot solve type `%s`", format(firstTid).ptr); 34:315: return session.error(scope.filename, firstTid.startPos, args); -:316: } -:317: 44:318: if t do -:319: { 4:320: s = t.asSymbol(); 4:321: node.solved = t; -:322: } 40:323: else do if s do -:324: { 40:325: node.solved = s.asType(); -:326: } 44:327: if s do -:328: { 43:329: checkDeprecated(node, s.astNode, scope); 43:330: scope.setSym(s); -:331: } 44:332: node.accept(this); 44:333: } -:334: -:335: @override function visitTypePointer(TypePointer* node) -:336: { 7511:337: scope = scope.pushNested(); 7511:338: node.modified = resolveType(node.modified, scope); 7511:339: scope = scope.pop(); 7511:340: if node.modified.resolved():u8* == TypeError.instance():u8* do -:341: { 4:342: node.free(); 4:343: result = TypeError.instance(); -:344: } 7511:345: } -:346: -:347: @override function visitTypeRcArray(TypeRcArray* node) -:348: { 789:349: scope = scope.pushNested(); 789:350: node.modified = resolveType(node.modified, scope); 789:351: scope = scope.pop(); -:352: 789:353: var auto tra = node.modified.asTypeRcArray(); 789:354: while tra do -:355: { 154:356: if node.nestedRcArrayDims == 15 do 1:357: session.error(scope.filename, node.startPos, "cannot nest more than 16 ref counted dimensions"); 154:358: ++node.nestedRcArrayDims; 154:359: tra = tra.modified.asTypeRcArray(); -:360: } 789:361: if isTypeError(node.modified) do -:362: { 1:363: node.free(); 1:364: result = TypeError.instance(); -:365: } 789:366: } -:367: -:368: @override function visitTypeSlice(TypeSlice* node) -:369: { 584:370: scope = scope.pushNested(); 584:371: node.modified = resolveType(node.modified, scope); 584:372: scope = scope.pop(); 584:373: if isTypeError(node.modified) do -:374: { 2:375: node.free(); 2:376: result = TypeError.instance(); -:377: } 584:378: } -:379: -:380: @override function visitTypeStaticArray(TypeStaticArray* node) -:381: { 344:382: scope = scope.pushNested(); 344:383: node.modified = resolveType(node.modified, scope); 344:384: scope = scope.pop(); 344:385: var auto tr = node.modified.resolved(); 344:386: if isTypeError(tr) do -:387: { 2:388: result = TypeError.instance(); 2:389: return; -:390: } 684:391: if var auto tes = asTypeTuple(tr) do 24:392: if var auto re = asRangeExp(node.lengthExp) do -:393: { 9:394: var auto te = (new TypeElements).create(tes, [node.lengthExp]); 9:395: result = te; 9:396: visitConcreteType(te); 9:397: return; -:398: } -:399: 333:400: var auto old = node.lengthExp; 333:401: scope = scope.pushNested(); 333:402: node.lengthExp = expressionSemantic(node.lengthExp, scope); 333:403: scope = scope.pop(); -:404: 666:405: if var auto e = evaluate(node.lengthExp) do 286:406: node.lengthExp = e; 333:407: if isTypeBool(tr) do -:408: { 44:409: var auto tex = asTypeExp(node.lengthExp); 44:410: var auto te = tex ? asTypeEnum(tex.type) 1:411: else node.lengthExp.symbol ? node.lengthExp.symbol.asType().asTypeEnum() 1:412: else null; -:413: 44:414: if te do -:415: { 43:416: var auto ed = te.declaration; 43:417: if ed.progress != SemanticProgress.done do 1:418: declarationSemantic(ed, ed.scope); 43:419: if isOrdered !in ed.flags do -:420: { 2:421: session.error(scope.filename, node.startPos, "cannot use `%s` as a set because the members are not ordered", format(te).ptr); -:422: } 43:423: if hasRoomForSet !in ed.flags do -:424: { 1:425: session.error(scope.filename, node.startPos, "cannot use `%s` as a set because the storage bitwidth (%d) is lesser than the member count (%d)", -:426: format(te).ptr, te.size, te.declaration.members.length); -:427: } 42:428: else do if inValueRange !in ed.flags do -:429: { 1:430: session.error(scope.filename, node.startPos, "cannot use `%s` as a set because the storage bitwidth (%d) is lesser than the member max value (%s)", -:431: format(te).ptr, te.size, format(te.declaration.max).ptr); -:432: } 43:433: result = (new TypeEnumSet).create(ed); 43:434: result.startPos = node.startPos; 43:435: return; -:436: } -:437: } 290:438: if !node.lengthExp || node.lengthExp.operator != TokenType.intLiteral do -:439: { 4:440: session.error(scope.filename, node.startPos, "static array dimension `%s` cannot be simplified to an integer", format(old).ptr); 4:441: return; -:442: } 286:443: if !node.modified || node.modified.resolved().size == 0 do 7:444: return; 279:445: const auto maxLen = u32.max / tr.size; 279:446: if node.length() > maxLen do 2:447: session.error(scope.filename, node.startPos, "static array with element type `%s` are limited to a length of `%d`", format(node.modified).ptr, maxLen); 279:448: node.size = node.modified.resolved().size * node.length(); 279:449: node.lengthExp.type = TypeUSize(); 279:450: } -:451: -:452: @override function visitTypeTuple(TypeTuple* node) -:453: { -:454: var usize numTypes; 52:455: foreach var auto t in node.types do -:456: { 124:457: t = resolveType(t, scope); 124:458: if isTypeError(t.resolved()) do 5:459: return (result = TypeError.instance()):(); 119:460: var auto tt = asTypeTuple(t); 119:461: numTypes += tt?.needsExpansion ? tt.types.length else 1; -:462: } 47:463: var auto types = (new Type*[+])(numTypes); -:464: var usize i; 47:465: foreach const auto t in node.types do -:466: { 115:467: var auto tt = asTypeTuple(t); 115:468: if !tt || !tt.needsExpansion do -:469: { 114:470: types[i++] = t; -:471: } -:472: else do -:473: { 1:474: types[i .. i + tt.types.length] = tt.types[0 .. $]; 1:475: i += tt.types.length; -:476: } -:477: } 47:478: node.types = types; 47:479: memulateTypeTuple(node, scope); 47:480: } -:481: -:482: @override function visitTypeUnambiguous(TypeUnambiguous* node) -:483: { 31:484: result = resolveType(node.unambiguous, scope); 31:485: } -:486:} <<<<<< EOF