diff --git a/cobc/ChangeLog b/cobc/ChangeLog index 01cd211af..df2d87184 100644 --- a/cobc/ChangeLog +++ b/cobc/ChangeLog @@ -1,4 +1,22 @@ +2026-08-26 Nicolas Berthier + + * tree.c (warn_if_no_definition_seen_for_prototype): move to typeck.c, + renamed into find_prototype_definition + * tree.c (cb_build_prototype): move check for missing definitions to the + (unique) call-site in typeck.c + * typeck.c (setup_prototype, check_prototype_against_definition): + report REPOSITORY entries that mismatch their definition + * typeck.c (try_get_program): handle USAGE OBJECT REFERENCE + * typeck.c (cb_check_conformance, cb_validate_oo_class_or_interface): + add support for checking method invocations, both via INVOKE or inline; + fix determination of last given argument + * parser.y (call_body): remove unneeded guard for call to + cb_check_conformance (now dealt with internally in try_get_program) + * parser.y (clean_up_program): proper module type in signature + * tree.c, tree.h (cb_build_field_reference): add const attributes to arguments + * tree.c, tree.h (cb_build_object_reference): new function + 2026-08-26 Fabrice Le Fessant * ppparse.y (ppp_replace_list_add): fix bug #1071 @@ -19,6 +37,17 @@ * field.c (warn_pic_for_numeric_value_implied): Added fix to print Implied PIC warning only when needed +2026-06-30 Saurabh Kumar + + * parser.y, reserved.c, scanner.l: add support for parsing INTERFACE-ID, + METHOD-ID, FACTORY, OBJECT paragraphs, INVOKE statement and inline method + invocation expression. Support CLASS and INTERFACE specifiers in REPOSITORY + paragraph. Also support keywords SELF and ACTIVE-CLASS. + * tree.h, tree.c, typeck.c: add syntax validation logic to check OO inheritance + list for duplicates, consistency with names specified in the REPOSITORY + paragraph + * cobc.h: add new special contexts for OO constructs + 2026-06-11 Saurabh Kumar * parser.y, reserved.c: add support for parsing class attributes - AS literal, diff --git a/cobc/cobc.h b/cobc/cobc.h index 73a3a005f..9573b1a51 100644 --- a/cobc/cobc.h +++ b/cobc/cobc.h @@ -177,6 +177,10 @@ enum cb_current_date { #define CB_CS_REPOSITORY (COB_U64_C(1) << 42) #define CB_CS_CALL_USING (COB_U64_C(1) << 43) /* within USING phrase of CALL statement */ #define CB_CS_READY_OR_RESET (COB_U64_C(1) << 44) +#define CB_CS_CLASS_SPECIFIER (COB_U64_C(1) << 45) +#define CB_CS_INTERFACE_SPECIFIER (COB_U64_C(1) << 46) +#define CB_CS_FACTORY_PARAGRAPH (COB_U64_C(1) << 47) +#define CB_CS_OBJECT_PARAGRAPH (COB_U64_C(1) << 48) /* Support for cobc from stdin */ #define COB_DASH "-" diff --git a/cobc/codegen.c b/cobc/codegen.c index 96224c017..c631d68c7 100644 --- a/cobc/codegen.c +++ b/cobc/codegen.c @@ -14052,14 +14052,14 @@ codegen_internal (struct cb_program *prog, const int subsequent_call) for (l = prog->entry_list; l; l = CB_CHAIN (l)) { output_function_entry_function (prog, l, 1); } - } else { + } else if (prog->prog_type == COB_MODULE_TYPE_PROGRAM) { output_line ("/* PROGRAM-ID '%s' */", prog->orig_program_id); output_newline (); for (l = prog->entry_list; l; l = CB_CHAIN (l)) { output_entry_function (prog, l, prog->parameter_list, 1); progid++; } - } + } /* TODO (OO): Handle other prog types. */ output_internal_function (prog, prog->parameter_list); diff --git a/cobc/parser.y b/cobc/parser.y index 806d2a443..57877618e 100644 --- a/cobc/parser.y +++ b/cobc/parser.y @@ -1471,7 +1471,7 @@ setup_program (cb_tree id, cb_tree as_literal, const enum cob_module_type type, /* build encoded external PROGRAM-ID */ current_program->program_id - = cb_build_program_id (external_name, type == COB_MODULE_TYPE_FUNCTION); + = cb_build_program_id (external_name, type != COB_MODULE_TYPE_PROGRAM); if (type == COB_MODULE_TYPE_PROGRAM) { if (!main_flag_set @@ -1529,12 +1529,18 @@ decrement_depth (const char *name, const unsigned char type) } else if (type == COB_MODULE_TYPE_CLASS) { cb_error (_("END CLASS '%s' is different from CLASS-ID '%s'"), name, stack_progid[depth]); + } else if (type == COB_MODULE_TYPE_INTERFACE) { + cb_error (_("END INTERFACE '%s' is different from INTERFACE-ID '%s'"), + name, stack_progid[depth]); + } else if (type == COB_MODULE_TYPE_METHOD) { + cb_error (_("END METHOD '%s' is different from METHOD-ID '%s'"), + name, stack_progid[depth]); } } } static void -clean_up_program (cb_tree name, const unsigned char type) +clean_up_program (cb_tree name, const enum cob_module_type type) { char *s; @@ -1547,6 +1553,10 @@ clean_up_program (cb_tree name, const unsigned char type) s = (char *)(CB_NAME (name)); } + /* CHECKME: shouldn' depth decrement also be perfomed when name + is not given? Maybe that's ok as per grammar rules that + force END-X to be followed by a name for every OO + construct... */ decrement_depth (s, type); } @@ -1660,7 +1670,7 @@ check_prototype_redefines_current_element (const cb_tree prototype_name) /* Returns 1 if the prototype has been duplicated. */ static int check_for_duplicate_prototype (const cb_tree prototype_name, - const cb_tree prototype) + const struct cb_prototype *prototype) { cb_tree dup; @@ -1673,9 +1683,8 @@ check_for_duplicate_prototype (const cb_tree prototype_name, } /* Check the duplicate prototypes match */ - if (strcmp (CB_PROTOTYPE (prototype)->ext_name, - CB_PROTOTYPE (dup)->ext_name) - || CB_PROTOTYPE (prototype)->type != CB_PROTOTYPE (dup)->type) { + if (strcmp (prototype->ext_name, CB_PROTOTYPE (dup)->ext_name) + || prototype->type != CB_PROTOTYPE (dup)->type) { cb_error_x (prototype_name, _("duplicate REPOSITORY entries for '%s' do not match"), get_literal_or_word_name (prototype_name)); @@ -1690,11 +1699,59 @@ check_for_duplicate_prototype (const cb_tree prototype_name, return 0; } +/* Note: neither proto nor program may be NULL */ +static void +check_prototype_against_definition (const struct cb_prototype *proto, + const struct cb_program *program) +{ + if (program->prog_type == proto->type) { + return; + } + cb_error_x (CB_TREE (proto), + _("%s REPOSITORY entry for '%s' does not match its definition"), + cb_get_cob_module_type_string (proto->type), + proto->ext_name); + cb_note_x (COB_WARNOPT_NONE, CB_TREE (program), + _("'%s' defined as a %s here"), + program->program_name, + cb_get_cob_module_type_string (program->prog_type)); +} + +static struct cb_program * +find_prototype_definition (const struct cb_prototype *proto) +{ + struct cb_program *program = NULL; + + program = cb_find_defined_program_by_id (proto->ext_name); + + if (!program && + get_warn_opt_value (cb_warn_ignored_initial_val) != COBC_WARN_DISABLED) { + if (strcmp (proto->name, proto->ext_name) == 0) { + /* + Warn if no definition seen for element with prototype- + name. + */ + cb_warning_x (cb_warn_prototypes, CB_TREE (proto), + _("no definition/prototype seen for %s '%s'"), + cb_get_cob_module_type_string (proto->type), proto->name); + } else { + /* + Warn if no definition seen for element with given + external-name. + */ + cb_warning_x (cb_warn_prototypes, CB_TREE (proto), + _("no definition/prototype seen for %s with external name '%s'"), + cb_get_cob_module_type_string (proto->type), proto->ext_name); + } + } + return program; +} + static void setup_prototype (cb_tree prototype_name, cb_tree ext_name, const enum cob_module_type type, const int is_current_element) { - cb_tree prototype; + struct cb_prototype *prototype; int name_redefinition_allowed; if (!is_current_element @@ -1702,28 +1759,47 @@ setup_prototype (cb_tree prototype_name, cb_tree ext_name, return; } - prototype = cb_build_prototype (prototype_name, ext_name, type); + prototype = CB_PROTOTYPE (cb_build_prototype (prototype_name, ext_name, type)); - if (!is_current_element - && check_for_duplicate_prototype (prototype_name, prototype)) { - return; + if (!is_current_element) { + const struct cb_program *program = find_prototype_definition (prototype); + if (check_for_duplicate_prototype (prototype_name, prototype)) { + return; + } + if (program) { + check_prototype_against_definition (prototype, program); + } } name_redefinition_allowed = type == COB_MODULE_TYPE_PROGRAM && is_current_element && cb_program_name_redefinition; if (!name_redefinition_allowed) { + cb_tree p = CB_TREE (prototype); if (CB_LITERAL_P (prototype_name)) { - cb_define (cb_build_reference ((const char *)CB_LITERAL (prototype_name)->data), prototype); + cb_define (cb_build_reference ((const char *)CB_LITERAL (prototype_name)->data), p); } else { - cb_define (prototype_name, prototype); + cb_define (prototype_name, p); } - if (type == COB_MODULE_TYPE_PROGRAM) { + switch (type) { + case COB_MODULE_TYPE_PROGRAM: current_program->program_spec_list = - cb_list_add (current_program->program_spec_list, prototype); - } else { /* COB_MODULE_TYPE_FUNCTION */ + cb_list_add (current_program->program_spec_list, p); + break; + case COB_MODULE_TYPE_FUNCTION: current_program->user_spec_list = - cb_list_add (current_program->user_spec_list, prototype); + cb_list_add (current_program->user_spec_list, p); + break; + case COB_MODULE_TYPE_CLASS: + current_program->class_spec_list = + cb_list_add (current_program->class_spec_list, p); + break; + case COB_MODULE_TYPE_INTERFACE: + current_program->interface_spec_list = + cb_list_add (current_program->interface_spec_list, p); + break; + case COB_MODULE_TYPE_METHOD: /* unreachable... (for now) */ + break; } } } @@ -2561,10 +2637,10 @@ set_record_size (cb_tree min, cb_tree max) } } -/* Object-oriented class */ +/* Object-orientation helpers */ static COB_INLINE void -set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) +set_oo_class_attr (enum cb_oo_class_attribute attr, const char* attr_name) { if (current_program->oo_class_attributes & attr) { emit_duplicate_clause_message (attr_name); @@ -2572,6 +2648,54 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) current_program->oo_class_attributes |= attr; } +/* Returns the program that corresponds to the currently defined class. + + Returns NULL outside of a method definition. */ +static struct cb_program * +current_self_class (void) { + struct cb_program *oo_class = current_program; + if (current_program->prog_type != COB_MODULE_TYPE_METHOD) { + cb_error (_("use of SELF outside of METHOD definition")); + return NULL; + } + while (oo_class && oo_class->prog_type == COB_MODULE_TYPE_METHOD) { + oo_class = oo_class->next_program; + } + return oo_class; +} + +/* Returns the program that corresponds to the super class of the currently + defined class, if it is unique and defined. Returns NULL in every other + case. + + Returns NULL outside of a method implementation. */ +static struct cb_program * +current_super_class (void) { + cb_tree super; + if (current_program->prog_type != COB_MODULE_TYPE_METHOD) { + cb_error (_("use of SUPER outside of METHOD definition")); + return NULL; + } + super = current_self_class ()->oo_inheritance_list; + if (unlikely (cb_list_length (super) == 0)) { + /* no declared inheritance (implcity Base)... */ + } else if (cb_list_length (super) == 1) { + super = cb_ref (CB_VALUE (super)); + if (CB_PROGRAM_P (super)) { + return CB_PROGRAM (super); + } else { + /* otherwise, it's only a prototype and we cannot check + much more at the moment... or do we? */ + } + } else { + /* multiple inheritance case */ + cb_warning (COBC_WARN_FILLER, + _("use of SUPER in CLASS or INTERFACE with " + "multiple inheritance may be ambiguous")); + } + return NULL; +} + %} %token TOKEN_EOF 0 "end of file" @@ -2703,7 +2827,7 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %token CLASS %token CLASS_ID "CLASS-ID" %token CLASSIFICATION -%token CLASS_NAME "class-name" +%token CLASS_NAME %token CLEAR_SELECTION "CLEAR-SELECTION" %token CLINE %token CLINES /* remark: not used here */ @@ -2838,20 +2962,24 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %token END_ACCEPT "END-ACCEPT" %token END_ADD "END-ADD" %token END_CALL "END-CALL" +%token END_CLASS "END CLASS" %token END_COMPUTE "END-COMPUTE" %token END_COLOR "END-COLOR" %token END_DELETE "END-DELETE" %token END_DISPLAY "END-DISPLAY" %token END_DIVIDE "END-DIVIDE" %token END_EVALUATE "END-EVALUATE" +%token END_FACTORY "END-FACTORY" %token END_FUNCTION "END FUNCTION" %token END_IF "END-IF" +%token END_INTERFACE "END INTERFACE" %token END_JSON "END-JSON" +%token END_METHOD "END METHOD" %token END_MODIFY "END-MODIFY" %token END_MULTIPLY "END-MULTIPLY" +%token END_OBJECT "END-OBJECT" %token END_PERFORM "END-PERFORM" %token END_PROGRAM "END PROGRAM" -%token END_CLASS "END CLASS" %token END_READ "END-READ" %token END_RECEIVE "END-RECEIVE" %token END_RETURN "END-RETURN" @@ -2895,6 +3023,7 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %token EXCLUSIVE %token EXHIBIT %token EXIT +%token EXPANDS %token EXPONENTIATION "exponentiation operator" %token EXTEND %token EXTENDED_SEARCH "EXTENDED-SEARCH" @@ -2954,6 +3083,7 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %token FUNCTION_NAME "intrinsic function name" %token FUNCTION_POINTER "FUNCTION-POINTER" %token GENERATE +%token GET %token GIVING %token GLOBAL %token GO @@ -2990,6 +3120,7 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %token IF %token IGNORE %token IGNORING +%token IMPLEMENTS %token IN %token INDEPENDENT %token INDEX @@ -3006,12 +3137,15 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %token INSERT_ROWS "INSERT-ROWS" %token INSPECT %token INSTALLATION /* remark: not used here */ +%token INTERFACE +%token INTERFACE_ID "INTERFACE-ID" %token INTERMEDIATE %token INTERNAL %token INTO %token INTRINSIC %token INVALID /* remark: not used here */ %token INVALID_KEY "INVALID KEY" +%token INVOKE %token IS %token ITEM %token ITEM_TEXT "ITEM-TEXT" @@ -3089,6 +3223,8 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %token MENU %token MERGE %token MESSAGE +%token METHOD +%token METHOD_ID %token MICROSECOND_TIME "MICROSECOND-TIME" %token MINUS %token MIN_VAL "MIN-VAL" @@ -3172,6 +3308,8 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %token ONLY %token ON_ESCAPE "ON ESCAPE" %token ON_EXCEPTION "ON EXCEPTION" +%token OO_CLASS_NAME "class-name" +%token OO_INTERFACE_NAME "interface-name" %token OPEN %token OPTIONAL %token OPTIONS @@ -3184,6 +3322,7 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %token OVERLAP_LEFT "OVERLAP-LEFT" %token OVERLAP_TOP "OVERLAP-TOP" %token OVERLINE +%token OVERRIDE %token PACKED_DECIMAL "PACKED-DECIMAL" %token PADDING %token PASCAL @@ -3339,6 +3478,7 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %token SELECTION_INDEX "SELECTION-INDEX" %token SELECTION_TEXT "SELECTION-TEXT" %token SELECT_ALL "SELECTION-ALL" +%token SELF %token SELF_ACT "SELF-ACT" %token SEMI_COLON "semi-colon" %token SEND @@ -3401,6 +3541,7 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %token SUBTRACT %token SUBWINDOW %token SUM +%token SUPER %token SUPPRESS %token SUPPRESS_XML "SUPPRESS" %token SYMBOL @@ -3438,6 +3579,7 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %token TOK_AMPER "&" %token TOK_CLOSE_PAREN ")" %token TOK_COLON ":" +%token TOK_COLON_COLON "::" %token TOK_DIV "/" %token TOK_DOT "." %token TOK_EQUAL "=" @@ -3593,6 +3735,7 @@ set_oo_class_attr(enum cb_oo_class_attribute attr, const char* attr_name) %nonassoc INITIATE %nonassoc INQUIRE %nonassoc INSPECT +%nonassoc INVOKE %nonassoc JSON %nonassoc MERGE %nonassoc MODIFY @@ -3747,6 +3890,7 @@ source_element: program_definition | class_definition | function_definition +| interface_definition | program_prototype | function_prototype ; @@ -3777,8 +3921,120 @@ program_definition: class_definition: _identification_header class_id_paragraph - /* TODO: _program_body */ + _class_body + { + cb_validate_program_data (current_program); + } end_class + { + cb_check_definition_matches_prototype (current_program); + } +; + +_class_body: + _options_paragraph + _environment_division + { + cb_validate_program_environment (current_program); + } + _factory_or_instance_definition +; + +interface_definition: + _identification_header + interface_id_paragraph + _interface_body + end_interface + { + cb_check_definition_matches_prototype (current_program); + } +; + +_interface_body: + _options_paragraph + _environment_division + { + cb_validate_program_environment (current_program); + cb_validate_program_data (current_program); + } + _procedure_division +; + +_factory_or_instance_definition: + /* empty */ +| factory_definition +| instance_definition +| factory_definition + instance_definition +; + +factory_definition: + _identification_header + FACTORY + { + __CS_ENTER (CB_CS_FACTORY_PARAGRAPH); + } + _dot + _implements_clause + { + __CS_LEAVE (CB_CS_FACTORY_PARAGRAPH); + } + _oo_body + { + /* TODO: use a flag to denote that those are factory method definitions, + or post-process the list of methods. The flag approach may be + necessary in case some checks performed during parsing depend on this + context. We could also generate distinct programs for factory and + for instance.. */ + } + END_FACTORY + _dot +; + +instance_definition: + _identification_header + OBJECT + { + __CS_ENTER (CB_CS_OBJECT_PARAGRAPH); + } + _dot + _implements_clause + { + __CS_LEAVE (CB_CS_OBJECT_PARAGRAPH); + } + _oo_body + END_OBJECT + _dot +; + +_oo_body: + _options_paragraph + _environment_division + { + cb_validate_program_environment (current_program); + } + _data_division + { + cb_validate_program_data (current_program); + } + _oo_procedure_division + { + /* Manual reset as a full OO construct like METHOD-ID can appear inside + PROCEDURE DIVISIONs. */ + cobc_in_procedure = 0; + } +; + +method_definition: + _identification_header + method_id_header TOK_DOT method_signature _override _is_final _dot + { + /* The PROCEDURE DIVISION is optional in methods definitions, so we'll + assume it is there already. */ + header_check |= COBC_HD_PROCEDURE_DIVISION; + } + _program_body + end_method ; function_definition: @@ -3821,11 +4077,36 @@ end_class: last_source_line = cb_source_line; check_area_a_of ("END CLASS"); } - end_class_name _dot + OO_CLASS_NAME _dot { + cobc_in_id = 0; clean_up_program ($3, COB_MODULE_TYPE_CLASS); } +; +end_interface: + END_INTERFACE + { + last_source_line = cb_source_line; + check_area_a_of ("END INTERFACE"); + } + interface_id_name _dot + { + cobc_in_id = 0; + clean_up_program ($3, COB_MODULE_TYPE_INTERFACE); + } +; + +end_method: + END_METHOD + { + last_source_line = cb_source_line; + check_area_a_of ("END METHOD"); + } + _method_id_name _dot + { + clean_up_program ($3, COB_MODULE_TYPE_METHOD); + } ; end_function: @@ -4007,29 +4288,49 @@ _default_display_clause: class_id_header: CLASS_ID { - cobc_in_id = 1; + __CS_CLEAR_ALL(); + CB_UNSUPPORTED ("object-oriented COBOL"); + } +; + +interface_id_header: + INTERFACE_ID + { + __CS_CLEAR_ALL(); + CB_UNSUPPORTED ("object-oriented COBOL (INTERFACE)"); } ; -class_id_name: - CLASS_NAME { $$ = $1; } +_method_id_name: + /* empty */ +| method_id_name +; + +method_id_name: + WORD | LITERAL { cb_trim_program_id ($1); } ; -parent_class_name: - WORD +interface_id_name: + WORD { $$ = $1; } +| LITERAL { - current_program->class_inheritance_list = - cb_list_add(current_program->class_inheritance_list, $1); + cb_trim_program_id ($1); } ; -parent_class_name_list: - parent_class_name -| parent_class_name_list parent_class_name +word_list: + WORD + { + $$ = CB_LIST_INIT ($1); + } +| word_list WORD + { + $$ = cb_list_add ($1, $2); + } ; /* Parameterized classes not supported for now. */ @@ -4040,7 +4341,10 @@ class_param_list: _inherits_phrase: /* empty */ -| INHERITS _from parent_class_name_list +| INHERITS _from word_list + { + current_program->oo_inheritance_list = $3; + } ; _using_phrase: @@ -4048,13 +4352,18 @@ _using_phrase: | USING class_param_list ; +_implements_clause: + /* empty */ +| IMPLEMENTS WORD _dot +; + class_attribute: - _is STATIC { set_oo_class_attr(CB_OO_CLASS_ATTR_STATIC, "STATIC"); } -| _is PARTIAL { set_oo_class_attr(CB_OO_CLASS_ATTR_PARTIAL, "PARTIAL"); } -| _is FINAL { set_oo_class_attr(CB_OO_CLASS_ATTR_FINAL, "FINAL"); } -| _is ABSTRACT { set_oo_class_attr(CB_OO_CLASS_ATTR_ABSTRACT, "ABSTRACT"); } -| _is PUBLIC { set_oo_class_attr(CB_OO_CLASS_ATTR_PUBLIC, "PUBLIC"); } -| _is INTERNAL { set_oo_class_attr(CB_OO_CLASS_ATTR_INTERNAL, "INTERNAL"); } + _is STATIC { set_oo_class_attr (CB_OO_CLASS_ATTR_STATIC, "STATIC"); } +| _is PARTIAL { set_oo_class_attr (CB_OO_CLASS_ATTR_PARTIAL, "PARTIAL"); } +| _is FINAL { set_oo_class_attr (CB_OO_CLASS_ATTR_FINAL, "FINAL"); } +| _is ABSTRACT { set_oo_class_attr (CB_OO_CLASS_ATTR_ABSTRACT, "ABSTRACT"); } +| _is PUBLIC { set_oo_class_attr (CB_OO_CLASS_ATTR_PUBLIC, "PUBLIC"); } +| _is INTERNAL { set_oo_class_attr (CB_OO_CLASS_ATTR_INTERNAL, "INTERNAL"); } ; _class_attributes: @@ -4073,21 +4382,16 @@ _class_attributes: */ class_id_paragraph: - class_id_header TOK_DOT class_id_name _as_literal + class_id_header TOK_DOT OO_CLASS_NAME _as_literal { - if (setup_program ($3, $4, COB_MODULE_TYPE_CLASS, 1)) { + if (setup_program ($3, $4, COB_MODULE_TYPE_CLASS, 0)) { YYABORT; } - - __CS_CLEAR_ALL(); - cobc_in_id = 0; - - CB_UNSUPPORTED ("object-oriented COBOL"); } _inherits_phrase _class_attributes _using_phrase - TOK_DOT + _dot { /* check consistency of current attribues */ if (current_program->oo_class_attributes & CB_OO_CLASS_ATTR_FINAL @@ -4103,11 +4407,46 @@ class_id_paragraph: } ; -end_class_name: - CLASS_NAME -| LITERAL +interface_id_paragraph: + interface_id_header TOK_DOT interface_id_name _as_literal { - cb_trim_program_id ($1); + if (setup_program ($3, $4, COB_MODULE_TYPE_INTERFACE, 0)) { + YYABORT; + } + } + _inherits_phrase + _using_phrase + _dot +; + +method_id_header: + METHOD_ID + { + __CS_CLEAR_ALL(); + } +; + +get_or_set: + GET +| SET +; + +method_signature: + method_id_name _as_literal + { + if (setup_program ($1, $2, COB_MODULE_TYPE_METHOD, 0)) { + YYABORT; + } + } +| get_or_set PROPERTY WORD + { + /* + TODO (OO): Call setup_program() with appropriate fields here. Also + set the property accessor type. + */ + if (setup_program ($3, NULL, COB_MODULE_TYPE_METHOD, 0)) { + YYABORT; + } } ; @@ -4122,12 +4461,18 @@ _program_body: } _data_division { - /* note: - we also validate all references we found so far here */ + /* note: we also validate all references we found so far here */ cb_validate_program_data (current_program); within_typedef_definition = 0; } _procedure_division + { + /* + Manual reset as a full OO construct like METHOD-ID can appear inside + PROCEDURE DIVISIONs. + */ + cobc_in_procedure = 0; + } ; /* IDENTIFICATION DIVISION */ @@ -4445,7 +4790,8 @@ configuration_header: { check_headers_present (COBC_HD_ENVIRONMENT_DIVISION, 0, 0, 0); header_check |= COBC_HD_CONFIGURATION_SECTION; - if (current_program->nested_level) { + if (current_program->nested_level + && current_program->prog_type == COB_MODULE_TYPE_PROGRAM) { cb_error (_("%s not allowed in nested programs"), "CONFIGURATION SECTION"); } } @@ -4675,6 +5021,18 @@ repository_list: | repository_list repository_name ; +_expands_clause: + /* empty */ +| EXPANDS WORD + { + /* + TODO (OO): Check that WORD is a class when used with the CLASS + specifier and interface when used with the INTERFACE specifier. + */ + } +USING word_list +; + repository_name: FUNCTION ALL INTRINSIC { @@ -4698,6 +5056,28 @@ repository_name: { yyerrok; } +| CLASS + { + __CS_ENTER (CB_CS_CLASS_SPECIFIER); + } + WORD _as_literal _expands_clause + { + if ($3 != cb_error_node) { + setup_prototype ($3, $4, COB_MODULE_TYPE_CLASS, 0); + } + __CS_LEAVE (CB_CS_CLASS_SPECIFIER); + } +| INTERFACE + { + __CS_ENTER (CB_CS_INTERFACE_SPECIFIER); + } + WORD _as_literal _expands_clause + { + if ($3 != cb_error_node) { + setup_prototype ($3, $4, COB_MODULE_TYPE_INTERFACE, 0); + } + __CS_LEAVE (CB_CS_INTERFACE_SPECIFIER); + } ; repository_name_list: @@ -8225,8 +8605,10 @@ type_to_clause: usage_clause: _usage_is usage -| USAGE _is conflict_usage /* auto-enters CB_CS_USAGE */ +| USAGE _is /* auto-enters CB_CS_USAGE */ + OBJECT REFERENCE _object_reference_type { + check_and_set_usage (CB_USAGE_OBJECT); __CS_LEAVE (CB_CS_USAGE); } | USAGE _is WORD /* MF extension for referencing types, full support would need @@ -8395,6 +8777,7 @@ usage: check_and_set_usage (CB_USAGE_POINTER); if ($2) { CB_PENDING ("POINTER TO type-name"); + current_field->reference = $2; } current_field->flag_is_pointer = 1; } @@ -8402,6 +8785,7 @@ usage: { check_and_set_usage (CB_USAGE_PROGRAM_POINTER); CB_PENDING ("POINTER TO prototype"); /* and function pointers... */ + current_field->reference = $2; current_field->flag_is_pointer = 1; } | PROGRAM_POINTER _to_program_type @@ -8409,6 +8793,7 @@ usage: check_and_set_usage (CB_USAGE_PROGRAM_POINTER); if ($2) { CB_PENDING ("POINTER TO prototype"); + current_field->reference = $2; } current_field->flag_is_pointer = 1; } @@ -8584,30 +8969,21 @@ _to_type_name: | _to type_name { $$ = $2; } ; -/* tokens that explicit need USAGE _is (because of reduce/reduce conflicts) */ -conflict_usage: - OBJECT REFERENCE _object_reference_type - { - check_and_set_usage (CB_USAGE_OBJECT); - CB_PENDING ("OBJECTS"); - } -; - _object_reference_type: /* empty */ -| WORD -| _factory_of ACTIVE_CLASS -| _factory_of CLASS_NAME _only +| OO_INTERFACE_NAME { current_field->reference = cb_ref ($1); } +| _factory_of ACTIVE_CLASS { current_field->reference = cb_int0; } +| _factory_of OO_CLASS_NAME _only { current_field->reference = cb_ref ($2); } ; _factory_of: - /* empty */ -| FACTORY _of + /* empty */ { current_field->flag_factory_reference = 0; } +| FACTORY _of { current_field->flag_factory_reference = 1; } ; _only: - /* empty */ { $$ = NULL; } -| ONLY { $$ = cb_int0; } + /* empty */ { current_field->flag_reference_only = 0; } +| ONLY { current_field->flag_reference_only = 1; } ; double_usage: @@ -9365,7 +9741,8 @@ _local_storage_section: check_headers_present (COBC_HD_DATA_DIVISION, 0, 0, 0); header_check |= COBC_HD_LOCAL_STORAGE_SECTION; current_storage = CB_STORAGE_LOCAL; - if (current_program->nested_level) { + if (current_program->nested_level + && current_program->prog_type == COB_MODULE_TYPE_PROGRAM) { cb_error (_("%s not allowed in nested programs"), "LOCAL-STORAGE"); } else if (cb_local_implies_recursive) { current_program->flag_recursive = 1; @@ -11217,7 +11594,7 @@ _procedure_division: | procedure_division ; -procedure_division: +procedure_division_header: PROCEDURE { check_area_a_of ("PROCEDURE DIVISION"); @@ -11228,6 +11605,7 @@ procedure_division: cobc_in_procedure = 1U; cb_set_system_names (); last_source_line = cb_source_line; + header_check |= COBC_HD_PROCEDURE_DIVISION; cb_prof_procedure_division ( current_program, @@ -11236,14 +11614,17 @@ procedure_division: ); } DIVISION +; + +procedure_division_sections: _mnemonic_conv _conv_linkage _procedure_using_chaining _procedure_returning { - cb_tree call_conv = $4; - if ($5) { - call_conv = $5; - if ($4) { - /* note: $3 is likely to be a reference to SPECIAL-NAMES */ - cb_error_x ($5, _("%s and %s are mutually exclusive"), + cb_tree call_conv = $1; + if ($2) { + call_conv = $2; + if ($1) { + /* note: $2 is likely to be a reference to SPECIAL-NAMES */ + cb_error_x ($2, _("%s and %s are mutually exclusive"), "CALL-CONVENTION", "WITH LINKAGE"); } } @@ -11256,17 +11637,16 @@ procedure_division: } else if (!current_program->entry_convention) { current_program->entry_convention = cb_int (CB_CONV_COBOL); } - header_check |= COBC_HD_PROCEDURE_DIVISION; } _dot_or_else_area_a _procedure_declaratives { if (current_program->flag_main - && !current_program->flag_chained && $6) { + && !current_program->flag_chained && $3) { cb_error (_("executable program requested but PROCEDURE/ENTRY has USING clause")); } - emit_main_entry (current_program, $6); + emit_main_entry (current_program, $3); cb_check_definition_matches_prototype (current_program); } @@ -11287,6 +11667,18 @@ procedure_division: emit_statement (cb_build_perform_exit (current_section)); } } +; + +_oo_procedure_division: + /* empty */ +| procedure_division_header + _dot_or_else_area_a + method_list +; + +procedure_division: + procedure_division_header + procedure_division_sections | { cb_tree label; @@ -11563,7 +11955,7 @@ _procedure_returning: } else if (f->flag_occurs) { cb_error (_("RETURNING item should not have OCCURS")); } else { - if (current_program->prog_type == COB_MODULE_TYPE_FUNCTION) { + if (current_program->prog_type != COB_MODULE_TYPE_PROGRAM) { if (f->flag_any_length) { cb_error (_("function RETURNING item may not be ANY LENGTH")); } @@ -11572,9 +11964,9 @@ _procedure_returning: #if 0 /* doesn't work for programs, will be fixed with allocating in the source-unit */ current_program->returning = $2; #else - if (current_program->prog_type == COB_MODULE_TYPE_FUNCTION) { + if (current_program->prog_type != COB_MODULE_TYPE_PROGRAM) { current_program->returning = $2; - } else { + } else if (current_program->prog_type == COB_MODULE_TYPE_PROGRAM) { CB_PENDING ("program RETURNING"); } #endif @@ -11662,6 +12054,12 @@ procedure: } ; +/* Method list */ + +method_list: + method_definition +| method_list method_definition +; /* Section/Paragraph */ @@ -11943,7 +12341,7 @@ statement: | initiate_statement | inquire_statement | inspect_statement -/* | TODO: invoke_statement */ +| invoke_statement | json_generate_statement | json_parse_statement | merge_statement @@ -12864,22 +13262,13 @@ call_body: } /* Check parameter conformance, if we can work out what is being called. */ - if (CB_LITERAL_P ($4)) { - cb_check_conformance ($4, $8, $9); - } else if (CB_REFERENCE_P ($4)) { - cb_tree ref = cb_ref ($4); - if ((CB_FIELD_P (ref) && CB_FIELD (ref)->flag_item_78) - || CB_PROGRAM_P (ref) - || CB_PROTOTYPE_P (ref)) { - cb_check_conformance ($4, $8, $9); - } - } + (void) cb_check_conformance ($4, NULL, $8, $9, 0); /* For CALL ... RETURNING NOTHING, set the call convention bit */ if (call_nothing) { call_conv |= CB_CONV_NO_RET_UPD; } - cb_emit_call ($4, $8, $9, CB_PAIR_X ($10), CB_PAIR_Y ($10), + cb_emit_call ($4, NULL, $8, $9, CB_PAIR_X ($10), CB_PAIR_Y ($10), cb_int (call_conv), $2, $6); emit_prof_call (COB_PROF_EXIT_CALL, target_name[0] == 0 ? "(dynamic)" : target_name, @@ -15271,6 +15660,24 @@ inspect_body: } ; +/* INVOKE statement */ + +invoke_statement: + INVOKE + id_or_class_name + id_or_lit + call_using + call_returning + { + (void) cb_check_conformance ($2, $3, $4, $5, 0); + } +; + +id_or_class_name: + identifier +| OO_CLASS_NAME +; + _backward: /* empty */ { $$ = NULL; } | BACKWARD { $$ = cb_int0; } @@ -19867,6 +20274,7 @@ identifier_or_file_name: $$ = cb_error_node; } } +| oo_identifier ; /* guarantees a reference to a validated field-reference (or cb_error_node) */ @@ -19905,6 +20313,44 @@ identifier: $$ = cb_error_node; } } +| oo_identifier +; + +/* TODO: make the semantic actions below return field references, so this can + then be merged into identifier_1? */ +oo_identifier: + SELF + { + cb_tree x = cb_validate_oo_class_or_interface (current_self_class ()); + if (x != cb_error_node) { + $$ = cb_build_object_reference (CB_PROGRAM (x), 0); + } else { + $$ = cb_error_node; + } + } +| SUPER + { + /* Note: warns in case of multiple inheritance... may we return a list + instead? */ + cb_tree x = cb_validate_oo_class_or_interface (current_super_class ()); + if (x != cb_error_node) { + $$ = cb_build_object_reference (CB_PROGRAM (x), 0); + } else { + $$ = cb_error_node; + } + } +| OO_CLASS_NAME OF SUPER + { + cb_tree x = cb_ref ($1); + if (CB_PROGRAM_P (x)) { + /* TODO: check super is actually inherited by the current + class... */ + x = cb_validate_oo_class_or_interface (CB_PROGRAM (x)); + $$ = cb_build_object_reference (CB_PROGRAM (x), 0); + } else { + $$ = cb_error_node; + } + } ; identifier_1: @@ -20337,6 +20783,49 @@ function: { $$ = cb_build_intrinsic ($1, $2, $3, 1); } +| id_or_class_name TOK_COLON_COLON literal inline_invoke_args + { + $$ = cb_check_conformance ($1, $3, $4, NULL, 1); + } +; + +inline_invoke_args: + /* empty */ %prec SHIFT_PREFER + { + $$ = NULL; + } +| TOK_OPEN_PAREN inline_invoke_args_list TOK_CLOSE_PAREN + { + if (cb_list_length ($2) > MAX_CALL_FIELD_PARAMS) { + cb_error_x (CB_TREE (current_statement), + _("number of arguments exceeds maximum %d"), + MAX_CALL_FIELD_PARAMS); + } + $$ = $2; + } +| TOK_OPEN_PAREN TOK_CLOSE_PAREN + { + $$ = NULL; + } +; + +inline_invoke_args_list: + inline_invoke_arg +| inline_invoke_args_list _e_sep inline_invoke_arg + { + $$ = cb_list_append ($1, $3); + } +; + +inline_invoke_arg: + OMITTED + { + $$ = CB_BUILD_PAIR (cb_int (CB_CALL_BY_REFERENCE), cb_null); + } +| exp %prec SHIFT_PREFER + { + $$ = cb_build_call_parameter ($1, CB_CALL_BY_REFERENCE, CB_SIZE_UNSET); + } ; func_no_parm: @@ -20880,6 +21369,7 @@ _is_equal: | IS | TOK_EQUAL; _is_are: | IS | ARE ; _is_are_equal: | IS | ARE | TOK_EQUAL; _is_in: | IS | IN ; +_is_final: | _is FINAL ; _key: | KEY ; _line: | LINE ; _line_or_lines: | LINE | LINES ; @@ -20897,6 +21387,7 @@ _on_for: | ON | FOR ; _onoff_status: | STATUS IS | STATUS | IS ; _other: | OTHER ; _others: | OTHERS ; +_override: | OVERRIDE ; _procedure: | PROCEDURE ; _program: | PROGRAM ; _protected: | PROTECTED ; diff --git a/cobc/reserved.c b/cobc/reserved.c index 4a92aecf0..ff8d5dfaf 100644 --- a/cobc/reserved.c +++ b/cobc/reserved.c @@ -1252,8 +1252,8 @@ static struct cobc_reserved default_reserved_words[] = { { "EXPAND", 0, 1, EXPAND, /* ACU extension */ 0, CB_CS_GRAPHICAL_CONTROL | CB_CS_INQUIRE_MODIFY }, - { "EXPANDS", 0, 1, -1, /* 2002 (C/S) */ - 0, 0 + { "EXPANDS", 0, 1, EXPANDS, /* 2002 (C/S) */ + 0, CB_CS_CLASS_SPECIFIER | CB_CS_INTERFACE_SPECIFIER /* FIXME: 2014 Context-sensitive to class-specifier and interface-specifier of REPOSITORY paragraph */ }, @@ -1442,8 +1442,8 @@ static struct cobc_reserved default_reserved_words[] = { { "GENERATE", 0, 0, GENERATE, /* 2002 */ 0, 0 }, - { "GET", 0, 0, -1, /* 2002 */ - 0, 0 + { "GET", 0, 0, GET, /* 2002 */ + 0, }, { "GIVING", 0, 0, GIVING, /* 2002 */ 0, 0 @@ -1562,8 +1562,8 @@ static struct cobc_reserved default_reserved_words[] = { { "IGNORING", 0, 1, IGNORING, /* 2002 (C/S) */ 0, CB_CS_READ }, - { "IMPLEMENTS", 0, 1, -1, /* 2002 (C/S) */ - 0, 0 + { "IMPLEMENTS", 0, 1, IMPLEMENTS, /* 2002 (C/S) */ + 0, CB_CS_FACTORY_PARAGRAPH | CB_CS_OBJECT_PARAGRAPH /* FIXME: 2014 Context-sensitive to FACTORY and OBJECT paragraph */ }, { "IN", 0, 0, IN, /* 2002 */ @@ -1617,10 +1617,10 @@ static struct cobc_reserved default_reserved_words[] = { { "INSTALLATION", 0, 1, INSTALLATION, /* 85 (later: C/S) */ 0, CB_CS_DAY /* HACK, we only want it to normally be not usable */ }, - { "INTERFACE", 0, 0, -1, /* 2002 */ + { "INTERFACE", 0, 0, INTERFACE, /* 2002 */ 0, 0 }, - { "INTERFACE-ID", 0, 0, -1, /* 2002 */ + { "INTERFACE-ID", 0, 0, INTERFACE_ID, /* 2002 */ 0, 0 }, { "INTERMEDIATE", 0, 1, INTERMEDIATE, /* 2014 (C/S) */ @@ -1638,7 +1638,7 @@ static struct cobc_reserved default_reserved_words[] = { { "INVALID", 0, 0, INVALID, /* 2002 */ 0, 0 }, - { "INVOKE", 0, 0, -1, /* 2002 */ + { "INVOKE", 0, 0, INVOKE, /* 2002 */ 0, 0 }, { "IS", 0, 0, IS, /* 2002 */ @@ -1870,10 +1870,10 @@ static struct cobc_reserved default_reserved_words[] = { { "MESSAGE-TAG", 0, 0, -1, /* COBOL 2023 MCS */ 0, 0 }, - { "METHOD", 0, 0, -1, /* 2002 */ + { "METHOD", 0, 0, METHOD, /* 2002 */ 0, 0 }, - { "METHOD-ID", 0, 0, -1, /* 2002 */ + { "METHOD-ID", 0, 0, METHOD_ID, /* 2002 */ 0, 0 }, { "MICROSECOND-TIME", 0, 1, MICROSECOND_TIME, /* ACU extension */ @@ -2605,7 +2605,7 @@ static struct cobc_reserved default_reserved_words[] = { { "SELECTION-TEXT", 0, 1, SELECTION_TEXT, /* ACU extension */ 0, CB_CS_GRAPHICAL_CONTROL | CB_CS_INQUIRE_MODIFY }, - { "SELF", 0, 0, -1, /* 2002 */ + { "SELF", 0, 0, SELF, /* 2002 */ 0, 0 }, { "SELF-ACT", 0, 1, SELF_ACT, /* ACU extension */ @@ -2799,7 +2799,7 @@ static struct cobc_reserved default_reserved_words[] = { { "SUM", 0, 0, SUM, /* 2002 */ 0, 0 }, - { "SUPER", 0, 0, -1, /* 2002 */ + { "SUPER", 0, 0, SUPER, /* 2002 */ 0, 0 }, { "SUPPRESS", 0, 0, SUPPRESS, /* 2002 */ diff --git a/cobc/scanner.l b/cobc/scanner.l index ae868118a..3ce2658ed 100644 --- a/cobc/scanner.l +++ b/cobc/scanner.l @@ -666,6 +666,26 @@ H#[0-9A-Za-z]+ { RETURN_TOK (END_CLASS); } +"END"[ ,;\n]+"FACTORY"/[ .,;\n] { + count_lines (yytext); + RETURN_TOK (END_FACTORY); +} + +"END"[ ,;\n]+"OBJECT"/[ .,;\n] { + count_lines (yytext); + RETURN_TOK (END_OBJECT); +} + +"END"[ ,;\n]+"METHOD"/[ .,;\n] { + count_lines (yytext); + RETURN_TOK (END_METHOD); +} + +"END"[ ,;\n]+"INTERFACE"/[ .,;\n] { + count_lines (yytext); + RETURN_TOK (END_INTERFACE); +} + "PICTURE"[ ,;\n]+"SYMBOL"/[ .,;\n] { if (lookup_reserved_word ("SYMBOL")) { count_lines (yytext); @@ -1064,10 +1084,10 @@ H#[0-9A-Za-z]+ { yylval = cb_build_alphanumeric_literal (yytext, (size_t)yyleng); RETURN_TOK (LITERAL); } - } else if ((second_last_token == CLASS_ID && last_token == TOK_DOT) - || last_token == END_CLASS) { + } else if ((second_last_token == CLASS_ID && last_token == TOK_DOT) + || last_token == END_CLASS) { yylval = cb_build_reference (yytext); - RETURN_TOK (CLASS_NAME); + RETURN_TOK (OO_CLASS_NAME); } /* Check reserved word */ @@ -1105,6 +1125,20 @@ H#[0-9A-Za-z]+ { RETURN_TOK (USER_FUNCTION_NAME); } } + for (l = current_program->class_spec_list; l; l = CB_CHAIN (l)) { + x = CB_VALUE (l); + if (!strcasecmp (yytext, CB_PROTOTYPE (x)->name)) { + yylval = cb_build_reference (yytext); + RETURN_TOK (OO_CLASS_NAME); + } + } + for (l = current_program->interface_spec_list; l; l = CB_CHAIN (l)) { + x = CB_VALUE (l); + if (!strcasecmp (yytext, CB_PROTOTYPE (x)->name)) { + yylval = cb_build_reference (yytext); + RETURN_TOK (OO_INTERFACE_NAME); + } + } if (cobc_allow_program_name) { for (l = current_program->program_spec_list; l; l = CB_CHAIN (l)) { x = CB_VALUE (l); @@ -1247,6 +1281,11 @@ H#[0-9A-Za-z]+ { RETURN_TOK (TOK_COLON); } +"::" { + yylval = NULL; + RETURN_TOK (TOK_COLON_COLON); +} + "=" { yylval = NULL; RETURN_TOK (TOK_EQUAL); diff --git a/cobc/tree.c b/cobc/tree.c index 75116f218..d639b3bef 100644 --- a/cobc/tree.c +++ b/cobc/tree.c @@ -1469,6 +1469,8 @@ cb_tree_category (cb_tree x) x->category = CB_CATEGORY_DATA_POINTER; } else if (f->usage == CB_USAGE_PROGRAM_POINTER) { x->category = CB_CATEGORY_PROGRAM_POINTER; + } else if (f->usage == CB_USAGE_OBJECT) { + x->category = CB_CATEGORY_OBJECT_REFERENCE; } else if (f->pic) { x->category = f->pic->category; /* FIXME: Hack for CGI to not abort */ @@ -5125,7 +5127,7 @@ cb_build_filler (void) If ref != NULL, other attributes are set to the same as ref. */ cb_tree -cb_build_field_reference (struct cb_field *f, cb_tree ref) +cb_build_field_reference (const struct cb_field *f, const cb_tree ref) { cb_tree x; struct cb_word *word; @@ -5141,6 +5143,27 @@ cb_build_field_reference (struct cb_field *f, cb_tree ref) return x; } +/* + Return a reference to the program p. + If ref != NULL, other attributes are set to the same as ref. +*/ +cb_tree +cb_build_object_reference (const struct cb_program *p, const cb_tree ref) +{ + cb_tree x; + struct cb_word *word; + + x = cb_build_reference (p->program_name); + word = CB_REFERENCE (x)->word; + if (ref) { + memcpy (x, ref, sizeof (struct cb_reference)); + } + x->category = CB_CATEGORY_OBJECT_REFERENCE; + CB_REFERENCE (x)->word = word; + CB_REFERENCE (x)->value = CB_TREE (p); + return x; +} + static void cb_define_system_name (const char *name) { @@ -6932,44 +6955,6 @@ cb_build_xml_parse (cb_tree data, cb_tree proc, /* Prototypes */ -static void -warn_if_no_definition_seen_for_prototype (const struct cb_prototype *proto) -{ - struct cb_program *program; - const char *error_msg; - - program = cb_find_defined_program_by_id (proto->ext_name); - if (program) { - return; - } - - if (get_warn_opt_value (cb_warn_ignored_initial_val) != COBC_WARN_DISABLED) { - if (strcmp (proto->name, proto->ext_name) == 0) { - /* - Warn if no definition seen for element with prototype- - name. - */ - if (proto->type == COB_MODULE_TYPE_FUNCTION) { - error_msg = _("no definition/prototype seen for FUNCTION '%s'"); - } else { /* PROGRAM_TYPE */ - error_msg = _("no definition/prototype seen for PROGRAM '%s'"); - } - cb_warning_x (cb_warn_prototypes, CB_TREE (proto), error_msg, proto->name); - } else { - /* - Warn if no definition seen for element with given - external-name. - */ - if (proto->type == COB_MODULE_TYPE_FUNCTION) { - error_msg = _("no definition/prototype seen for FUNCTION with external name '%s'"); - } else { /* PROGRAM_TYPE */ - error_msg = _("no definition/prototype seen for PROGRAM with external name '%s'"); - } - cb_warning_x (cb_warn_prototypes, CB_TREE (proto), error_msg, proto->ext_name); - } - } -} - cb_tree cb_build_prototype (const cb_tree prototype_name, const cb_tree ext_name, const enum cob_module_type type) @@ -7001,8 +6986,6 @@ cb_build_prototype (const cb_tree prototype_name, const cb_tree ext_name, prototype->type = type; - warn_if_no_definition_seen_for_prototype (prototype); - return CB_TREE (prototype); } @@ -7670,6 +7653,35 @@ cb_build_prof_call (enum cb_prof_call prof_call, return CB_BUILD_FUNCALL_3 (func_name, cb_int (prof_call), cb_int (func_arg1), cb_int (func_arg2)); } +/* Object-oriented */ + +const char * +cb_get_cob_module_type_string (enum cob_module_type prog_type) +{ + switch (prog_type) { + default: + case COB_MODULE_TYPE_PROGRAM: return "PROGRAM"; + case COB_MODULE_TYPE_FUNCTION: return "FUNCTION"; + case COB_MODULE_TYPE_CLASS: return "CLASS"; + case COB_MODULE_TYPE_INTERFACE: return "INTERFACE"; + case COB_MODULE_TYPE_METHOD: return "METHOD"; + } +} + +int +cb_search_in_prototypes (cb_tree list, cb_tree name) +{ + cb_tree l; + + for (l = list; l; l = CB_CHAIN (l)) { + const char * const x_name = CB_PROTOTYPE (CB_VALUE (l))->name; + if (strcasecmp (x_name, CB_NAME (name)) == 0) { + return 0; + } + } + return 1; +} + /* Allocate a procedure description record and add it at the end of * the procedure_list of the current program. The index of the * procedure will be the position in the list. There is an invariant diff --git a/cobc/tree.h b/cobc/tree.h index 1e72b9b76..f8ad700bd 100644 --- a/cobc/tree.h +++ b/cobc/tree.h @@ -525,6 +525,13 @@ enum cb_oo_class_attribute { CB_OO_CLASS_ATTR_INTERNAL = 0x20 }; +/* Object-orinted method property accessor type */ +enum cb_oo_property_accessor { + CB_OO_ACCESS_NONE = 0, /* Default, the method is neither a getter nor a setter */ + CB_OO_ACCESS_GET = 1, /* Getter method */ + CB_OO_ACCESS_SET = 2 /* Setter method */ +}; + /* Reserved word list structure */ struct cobc_reserved { @@ -921,6 +928,7 @@ struct cb_field { cb_tree external_definition; /* by SAME AS / LIKE data-name or by type-name (points to field) */ cb_tree like_modifier; /* set for LIKE, may contain a length modifier */ + cb_tree reference; int id; /* Field id */ int size; /* Field size */ @@ -1018,6 +1026,8 @@ struct cb_field { unsigned int flag_is_verified : 1; /* Has been verified */ unsigned int flag_had_definition_note : 1; /* had its defintion output */ + unsigned int flag_factory_reference : 1; /* OBJECT REFERENCE FACTORY */ + unsigned int flag_reference_only : 1; /* OBJECT REFERENCE _ ONLY */ }; #define CB_FIELD(x) (CB_TREE_CAST (CB_TAG_FIELD, struct cb_field, x)) @@ -1408,6 +1418,7 @@ struct cb_xml_parse { struct cb_call { struct cb_tree_common common; /* Common values */ + cb_tree obj_or_class; /* INVOKE class name or object reference */ cb_tree name; /* CALL name */ cb_tree args; /* Arguments */ cb_tree stmt1; /* ON EXCEPTION */ @@ -1832,6 +1843,9 @@ struct nested_list { struct cb_program *nested_prog; }; +/* CHECKME: a new struct cb_object_class (and cb_object_class_signature?) with + specific fields would be convenient when it comes to further + type-checking... */ struct cb_program { struct cb_tree_common common; /* Common values */ @@ -1869,13 +1883,13 @@ struct cb_program { cb_tree cb_sort_return; /* SORT-RETURN */ cb_tree cb_call_params; /* Number of CALL params */ cb_tree mnemonic_spec_list; /* MNEMONIC spec */ - cb_tree class_spec_list; /* CLASS spec */ - cb_tree interface_spec_list; /* INTERFACE spec */ + cb_tree class_spec_list; /* CLASS spec (prototypes only) */ + cb_tree interface_spec_list; /* INTERFACE spec (prototypes only) */ cb_tree function_spec_list; /* FUNCTION spec */ cb_tree user_spec_list; /* User FUNCTION spec */ cb_tree program_spec_list; /* PROGRAM spec */ cb_tree property_spec_list; /* PROPERTY spec */ - cb_tree class_inheritance_list; /* List of Inherited Classes (OOP) */ + cb_tree oo_inheritance_list; /* List of Inherited Classes (OOP) */ struct cb_alter_id *alter_gotos; /* ALTER ids */ struct cb_field *working_storage; /* WORKING-STORAGE */ struct cb_field *local_storage; /* LOCAL-STORAGE */ @@ -1926,7 +1940,7 @@ struct cb_program { cob_u8_t high_value; /* High-value for this program */ cob_u16_t low_value_n; /* National Low-value */ cob_u16_t high_value_n; /* National High-value */ - enum cob_module_type prog_type; /* Program type (program = 0, function = 1, OO class = 2) */ + enum cob_module_type prog_type; /* Program type */ cob_u8_t oo_class_attributes; /* OO class attributes */ cb_tree entry_convention; /* ENTRY convention / PROCEDURE convention */ struct literal_list *decimal_constants; @@ -1967,7 +1981,7 @@ struct cb_program { #define CB_PROGRAM(x) (CB_TREE_CAST (CB_TAG_PROGRAM, struct cb_program, x)) #define CB_PROGRAM_P(x) (CB_TREE_TAG (x) == CB_TAG_PROGRAM) -/* Function prototype */ +/* Prototype (function, class, or interface) */ struct cb_prototype { struct cb_tree_common common; @@ -2173,8 +2187,10 @@ extern void cb_finalize_cd (struct cb_cd *, extern cb_tree cb_build_filler (void); extern cb_tree cb_build_reference (const char *); -extern cb_tree cb_build_field_reference (struct cb_field *, - cb_tree); +extern cb_tree cb_build_field_reference (const struct cb_field *, + const cb_tree); +extern cb_tree cb_build_object_reference (const struct cb_program *, + const cb_tree); extern const char *cb_define (cb_tree, cb_tree); extern char *cb_to_cname (const char *); extern void cb_set_system_names (void); @@ -2415,6 +2431,9 @@ extern void cb_validate_program_environment (struct cb_program *); extern void cb_validate_program_data (struct cb_program *); extern void cb_validate_program_body (struct cb_program *); +extern void cb_validate_oo_program_data (struct cb_program *); +extern cb_tree cb_validate_oo_class_or_interface (struct cb_program *); + extern cb_tree cb_build_expr (cb_tree); extern cb_tree cb_build_cond (cb_tree); @@ -2464,7 +2483,7 @@ extern void cb_emit_allocate_characters (cb_tree, cb_tree, cb_tree); extern void cb_emit_alter (cb_tree, cb_tree); extern void cb_emit_free (cb_tree); -extern void cb_emit_call (cb_tree, cb_tree, cb_tree, cb_tree, +extern void cb_emit_call (cb_tree, cb_tree, cb_tree, cb_tree, cb_tree, cb_tree, cb_tree, cb_tree, cb_tree); extern void cb_emit_cancel (cb_tree); @@ -2601,7 +2620,8 @@ extern cb_tree cb_build_write_advancing_lines (cb_tree, cb_tree); extern cb_tree cb_build_write_advancing_mnemonic (cb_tree, cb_tree); extern cb_tree cb_build_write_advancing_page (cb_tree); extern cb_tree cb_check_sum_field (cb_tree x); -extern void cb_check_conformance (cb_tree, cb_tree, cb_tree); +extern cb_tree cb_check_conformance (cb_tree, cb_tree, cb_tree, cb_tree, + int inline_invocation); extern void cb_emit_initiate (cb_tree rep); extern void cb_emit_terminate (cb_tree rep); extern void cb_emit_generate (cb_tree rep); @@ -2617,6 +2637,9 @@ extern cb_tree cb_build_xml_parse (cb_tree, cb_tree, extern void cb_emit_json_generate (cb_tree, cb_tree, cb_tree, cb_tree, cb_tree); +extern const char *cb_get_cob_module_type_string (enum cob_module_type); +extern int cb_search_in_prototypes (cb_tree prototypes, cb_tree name); + #ifdef COB_TREE_DEBUG extern cb_tree cobc_tree_cast_check (const cb_tree, const char *, const int, const enum cb_tag); diff --git a/cobc/typeck.c b/cobc/typeck.c index f29df4c8d..df675130a 100644 --- a/cobc/typeck.c +++ b/cobc/typeck.c @@ -3064,6 +3064,21 @@ set_argument_defaults (cb_tree argument, cb_tree parameter, const struct cb_fiel } +cb_tree +cb_validate_oo_class_or_interface (struct cb_program *prog) { + if (!prog) { + return cb_error_node; + } + if (prog->prog_type != COB_MODULE_TYPE_CLASS + && prog->prog_type != COB_MODULE_TYPE_INTERFACE) { + cb_error_x (CB_TREE (prog), + _("CLASS or INTERFACE expected (got %s '%s')"), + cb_get_cob_module_type_string (prog->prog_type), + prog->program_name); + return cb_error_node; + } + return CB_TREE (prog); +} void cb_validate_parameters_and_returning (struct cb_program *prog, cb_tree using_list) @@ -3153,6 +3168,26 @@ cb_validate_parameters_and_returning (struct cb_program *prog, cb_tree using_lis } } +/* Returns NULL on figurative constants */ +static COB_INLINE const char * +try_get_literal_data (cb_tree ref) { + if (CB_LITERAL_P (ref)) { + return (char *) CB_LITERAL (ref)->data; + } else if (CB_REFERENCE_P (ref)) { + ref = cb_ref (ref); + if (ref == cb_error_node) { + return NULL; + } + if (CB_FIELD_P (ref) && CB_FIELD (ref)->flag_item_78) { + cb_tree x = CB_VALUE (CB_FIELD (ref)->values); + if (!CB_LITERAL_P (x)) { + return NULL; + } + return (char *) CB_LITERAL (x)->data; + } + } + return NULL; +} /* TODO: Add params differing in BY REFERENCE/VALUE and OPTIONAL to testsuite */ @@ -3163,26 +3198,25 @@ try_get_program (cb_tree prog_ref) const char *name_str; cb_tree ref; - if (CB_LITERAL_P (prog_ref) + name_str = try_get_literal_data (prog_ref); + if (name_str /* && TODO: Check user wants checks on this kind of CALL. */) { - name_str = (char *) CB_LITERAL (prog_ref)->data; program = cb_find_defined_program_by_name (name_str); } else if (CB_REFERENCE_P (prog_ref)) { ref = cb_ref (prog_ref); if (ref == cb_error_node) { return NULL; } - - if (CB_FIELD_P (ref) && CB_FIELD (ref)->flag_item_78 - /* && TODO: Check user wants checks on this kind of CALL. */) { - cb_tree x = CB_VALUE (CB_FIELD (ref)->values); - if (!CB_LITERAL_P (x)) { - /* in theory this could be a figurative constant, - in this case there is no matching program */ - return NULL; + if (CB_FIELD_P (ref) + && CB_FIELD (ref)->usage == CB_USAGE_OBJECT + && CB_FIELD (ref)->reference) { + cb_tree x = CB_FIELD (ref)->reference; + if (CB_PROGRAM_P (x)) { + program = CB_PROGRAM (x); + } else if (CB_PROTOTYPE_P (x)) { + name_str = CB_PROTOTYPE (x)->ext_name; + program = cb_find_defined_program_by_id (name_str); } - name_str = (char *) CB_LITERAL (x)->data; - program = cb_find_defined_program_by_name (name_str); } else if (CB_PROTOTYPE_P (ref)) { name_str = CB_PROTOTYPE (ref)->ext_name; program = cb_find_defined_program_by_id (name_str); @@ -3565,7 +3599,7 @@ check_argument_conformance (struct cb_program *program, cb_tree argument_tripple return; } - param_ref = cb_build_field_reference ((struct cb_field *)param_field, NULL); + param_ref = cb_build_field_reference (param_field, NULL); /* Check the definition of the argument is compatible with the parameter. @@ -3630,9 +3664,27 @@ check_argument_conformance (struct cb_program *program, cb_tree argument_tripple } } -void -cb_check_conformance (cb_tree prog_ref, cb_tree using_list, - cb_tree returning) +static struct cb_program * +try_get_method (struct cb_program *class, cb_tree oo_method_name) { + struct cb_program *method = NULL; + const char * method_name = try_get_literal_data (oo_method_name); + if (method_name) { + struct nested_list* m; + for (m = class->nested_prog_list; m && !method; m = m->next) { + if (strcasecmp (method_name, m->nested_prog->program_name) == 0) { + method = m->nested_prog; + } + } + } + return method; +} + +/* When inline_invocation is set, returns a reference to the field of the + *CALLED* program/function/method if it is found, or cb_error_node otheriwse. + This is used for type-checking inline method invocations. */ +cb_tree +cb_check_conformance (cb_tree prog_ref, cb_tree oo_method_name, cb_tree using_list, + cb_tree returning, int inline_invocation) { struct cb_program *program = NULL; cb_tree l; @@ -3642,15 +3694,37 @@ cb_check_conformance (cb_tree prog_ref, cb_tree using_list, const struct cb_field *prog_returning_field; const struct cb_field *call_returning_field; - /* Try to get the program referred to by prog_ref. */ - program = try_get_program (prog_ref); + if (oo_method_name) { + /* prog_ref may be either: (i) a user-defined class or interface + name (listed in the REPOSITORY paragraph); (ii) an identifier + (expected with usage OBJECT REFERENCE, maybe to a factory); + (iii) SELF (cb_int0); or SUPER (cb_int1). */ + struct cb_program *oo_class = NULL; + int factory_method_invocation = 0; + if (CB_PROGRAM_P (prog_ref)) { + oo_class = CB_PROGRAM (prog_ref); + factory_method_invocation = 1; + } else { + /* TODO: decompose that check to set + factory_method_invocation when needed */ + oo_class = try_get_program (prog_ref); + } + COB_UNUSED (factory_method_invocation); /* for now */ + l = cb_validate_oo_class_or_interface (oo_class); + /* TODO: Walk up the class hierarchy/DAG, starting from + oo_class, checking matching methods... For now we only check + a method in oo_class, if any. */ + if (l != cb_error_node) { + program = try_get_method (CB_PROGRAM (l), oo_method_name); + } + } else { + program = try_get_program (prog_ref); + } if (!program) { - /* - */ for (l = using_list; l; l = CB_CHAIN (l)) { set_argument_defaults (l, NULL, NULL); } - return; + return cb_error_node; } /* @@ -3662,8 +3736,8 @@ cb_check_conformance (cb_tree prog_ref, cb_tree using_list, l && param_num <= program->num_proc_params; l = CB_CHAIN (l), ++param_num) { check_argument_conformance (program, l, param_num); - last_arg = l; } + last_arg = l; /* If there are more params in the using list than in the prototype, error */ if (l && param_num > program->num_proc_params) { @@ -3717,11 +3791,19 @@ cb_check_conformance (cb_tree prog_ref, cb_tree using_list, } else if (returning && !program->returning) { /* CHECKME: do we want to cater for RETURNING internally setting RETURN-CODE? */ cb_warning_x (cb_warn_repository_checks, returning, - _("unexpected RETURNING item")); - } else if (!returning && program->returning) { - cb_warning_x (cb_warn_repository_checks, returning, - _("expecting a RETURNING item, but none provided")); + _("unexpected RETURNING item")); + } else if (inline_invocation && !program->returning) { + cb_warning (cb_warn_repository_checks, + _("invalid inline invocation of a method with no RETURNING")); + } else if (!returning && !inline_invocation && program->returning) { + cb_warning (cb_warn_repository_checks, + _("expecting a RETURNING item, but none provided")); } + + if (program->returning && inline_invocation) { + return program->returning; + } + return cb_error_node; } static int @@ -4814,6 +4896,46 @@ validate_assign_name (cb_tree origin, struct cb_program * const prog) } } +void +cb_validate_oo_program_data (struct cb_program *prog) { + cb_tree l, x, inheritable_prototypes = NULL; + + if (prog->prog_type == COB_MODULE_TYPE_CLASS) { + inheritable_prototypes = prog->class_spec_list; + } else /* if (prog->prog_type == COB_MODULE_TYPE_INTERFACE) */ { + inheritable_prototypes = prog->interface_spec_list; + } + for (l = prog->oo_inheritance_list; l; l = CB_CHAIN (l)) { + const cb_tree y = CB_VALUE (l); + if (strcasecmp (prog->program_id, CB_NAME (y)) == 0) { + cb_error_x (l, _("cyclically inheriting %s '%s'"), + cb_get_cob_module_type_string (prog->prog_type), + CB_NAME (y)); + cb_note_x (COB_WARNOPT_NONE, CB_TREE (prog), _("'%s' defined here"), + CB_NAME (y)); + } + + /* Check for parent name in REPOSITORY paragraph */ + if (cb_search_in_prototypes (inheritable_prototypes, y) == 1) { + cb_error_x (l, _("inherited %s '%s' not found in REPOSITORY paragraph"), + cb_get_cob_module_type_string (prog->prog_type), + CB_NAME (y)); + } + + /* Check for duplicate parent name */ + for (x = CB_CHAIN (l); x; x = CB_CHAIN (x)) { + if (strcasecmp (CB_NAME (y), CB_NAME (CB_VALUE (x))) == 0) { + cb_error_x (x, _("duplicate parent %s '%s'"), + cb_get_cob_module_type_string (prog->prog_type), + CB_NAME (CB_VALUE (x))); + cb_note_x (COB_WARNOPT_NONE, l, _("'%s' defined here"), + CB_NAME (y)); + break; + } + } + } +} + void cb_validate_program_data (struct cb_program *prog) { @@ -4911,6 +5033,11 @@ cb_validate_program_data (struct cb_program *prog) and free it here directly */ } + if (prog->prog_type == COB_MODULE_TYPE_CLASS + || prog->prog_type == COB_MODULE_TYPE_INTERFACE) { + cb_validate_oo_program_data (prog); + } + /* Check ODO items */ for (l = cb_depend_check; l; l = CB_CHAIN (l)) { struct cb_field *depfld = NULL; @@ -8799,7 +8926,7 @@ get_constant_call_name (cb_tree prog) } void -cb_emit_call (cb_tree prog, cb_tree par_using, cb_tree returning, +cb_emit_call (cb_tree prog, cb_tree oo_method, cb_tree par_using, cb_tree returning, cb_tree on_exception, cb_tree not_on_exception, cb_tree convention, cb_tree newthread, cb_tree handle) { @@ -8820,6 +8947,8 @@ cb_emit_call (cb_tree prog, cb_tree par_using, cb_tree returning, int call_conv; unsigned int numargs; + COB_UNUSED (oo_method); + if (CB_INTRINSIC_P (prog)) { if (CB_INTRINSIC (prog)->intr_tab->category != CB_CATEGORY_ALPHANUMERIC) { cb_error_x (CB_TREE (current_statement), diff --git a/libcob/ChangeLog b/libcob/ChangeLog index 77bfbf84a..af9fc8ae8 100644 --- a/libcob/ChangeLog +++ b/libcob/ChangeLog @@ -6,6 +6,11 @@ and fflush only is last operation was a write * call.c (cob_get_buff): protect call to cob_free +2026-06-30 Saurabh Kumar + + * common.h (cob_module_type): add COB_MODULE_TYPE_CLASS, + COB_MODULE_TYPE_INTERFACE, COB_MODULE_TYPE_METHOD + 2026-03-02 Fabrice Le Fessant * coblocal.h, common.c, profiling.c: rename is_test to cob_is_test diff --git a/libcob/common.h b/libcob/common.h index b2b3167d2..9329daef6 100644 --- a/libcob/common.h +++ b/libcob/common.h @@ -1252,7 +1252,9 @@ typedef struct __cob_screen { enum cob_module_type { COB_MODULE_TYPE_PROGRAM = 0, COB_MODULE_TYPE_FUNCTION = 1, - COB_MODULE_TYPE_CLASS = 2 + COB_MODULE_TYPE_CLASS = 2, + COB_MODULE_TYPE_INTERFACE = 3, + COB_MODULE_TYPE_METHOD = 4 }; /* diff --git a/tests/testsuite.src/syn_definition.at b/tests/testsuite.src/syn_definition.at index 17e49ee9f..a8ff76dcd 100644 --- a/tests/testsuite.src/syn_definition.at +++ b/tests/testsuite.src/syn_definition.at @@ -1276,7 +1276,7 @@ AT_DATA([prog.cob], [ ]) AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], -[prog.cob:3: error: syntax error, unexpected IDENTIFICATION, expecting CLASS-ID or FUNCTION-ID or PROGRAM-ID +[prog.cob:3: error: syntax error, unexpected IDENTIFICATION, expecting CLASS-ID or FUNCTION-ID or INTERFACE-ID or PROGRAM-ID ]) AT_CLEANUP diff --git a/tests/testsuite.src/syn_misc.at b/tests/testsuite.src/syn_misc.at index 8f239fefd..2de35319a 100644 --- a/tests/testsuite.src/syn_misc.at +++ b/tests/testsuite.src/syn_misc.at @@ -3987,12 +3987,12 @@ AT_DATA([prog.cob], [ AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], [prog.cob:12: error: syntax error, unexpected DELIMITED prog.cob:15: error: syntax error, unexpected END-STRING, expecting INTO -prog.cob:17: error: syntax error, unexpected END-STRING, expecting Identifier +prog.cob:17: error: syntax error, unexpected END-STRING, expecting class-name or SELF or SUPER or Identifier prog.cob:19: error: syntax error, unexpected DELIMITED prog.cob:24: error: syntax error, unexpected DELIMITED, expecting INTO prog.cob:32: error: syntax error, unexpected DELIMITED prog.cob:34: error: syntax error, unexpected Identifier, expecting INTO -prog.cob:37: error: syntax error, unexpected END-UNSTRING, expecting Identifier +prog.cob:37: error: syntax error, unexpected END-UNSTRING, expecting class-name or SELF or SUPER or Identifier prog.cob:38: error: syntax error, unexpected DELIMITED prog.cob:43: error: syntax error, unexpected DELIMITED, expecting INTO ]) @@ -4371,8 +4371,8 @@ prog.cob:22: error: 'f' is not a field prog.cob:22: error: 3 is not an alphanumeric literal prog.cob:22: error: 2 is not an alphanumeric literal prog.cob:22: error: invalid target for TRANSFORM -prog.cob:23: error: syntax error, unexpected intrinsic function name, expecting Identifier -prog.cob:24: error: syntax error, unexpected Literal, expecting Identifier +prog.cob:23: error: syntax error, unexpected intrinsic function name, expecting class-name or SELF or SUPER or Identifier +prog.cob:24: error: syntax error, unexpected Literal, expecting class-name or SELF or SUPER or Identifier prog.cob:25: error: invalid target for REPLACING ]) AT_CLEANUP @@ -6565,7 +6565,7 @@ prog.cob:49: error: JSON/XML GENERATE receiving item must be alphanumeric or nat prog.cob:51: error: JSON/XML GENERATE receiving item may not have JUSTIFIED clause prog.cob:53: error: JSON/XML GENERATE receiving item may not be subscripted prog.cob:54: error: JSON/XML GENERATE receiving item may not be reference modified -prog.cob:57: error: syntax error, unexpected intrinsic function name, expecting Identifier +prog.cob:57: error: syntax error, unexpected intrinsic function name, expecting class-name or SELF or SUPER or Identifier prog.cob:59: error: JSON/XML GENERATE input record may not be reference modified prog.cob:61: error: JSON/XML GENERATE input record may not have RENAMES clause prog.cob:66: error: JSON/XML GENERATE input record has subrecords with non-unique names @@ -6603,7 +6603,7 @@ prog.cob:133: error: SUPPRESS item with WHEN clause must be elementary prog.cob:133: error: SUPPRESS item must be a child of the input record prog.cob:132: error: SUPPRESS item may not be an ignored item in JSON/XML GENERATE prog.cob:132: error: SUPPRESS item with WHEN clause must be elementary -prog.cob:136: error: syntax error, unexpected intrinsic function name, expecting EVERY or WHEN or Identifier +prog.cob:136: error: syntax error, unexpected intrinsic function name prog.cob:142: warning: OCCURS items in JSON/XML GENERATE is not implemented prog.cob:140: error: SUPPRESS item may not be subscripted prog.cob:139: error: SUPPRESS item may not be reference modified diff --git a/tests/testsuite.src/syn_oo.at b/tests/testsuite.src/syn_oo.at index e8f320c26..93f00a6c4 100644 --- a/tests/testsuite.src/syn_oo.at +++ b/tests/testsuite.src/syn_oo.at @@ -50,8 +50,8 @@ AT_DATA([prog1.cob], [ ]) AT_CHECK([$COMPILE_ONLY prog1.cob], [1], [], -[prog1.cob:3: error: object-oriented COBOL is not supported -prog1.cob:4: error: syntax error, unexpected ., expecting class-name or Literal +[prog1.cob:3: error: object-oriented COBOL is not supported +prog1.cob:4: error: syntax error, unexpected ., expecting class-name ]) AT_DATA([prog2.cob], [ @@ -62,18 +62,23 @@ AT_DATA([prog2.cob], [ AT_CHECK([$COMPILE_ONLY prog2.cob], [1], [], [prog2.cob:3: error: object-oriented COBOL is not supported -prog2.cob:4: error: syntax error, unexpected END PROGRAM, expecting END CLASS +prog2.cob:4: error: syntax error, unexpected END PROGRAM, expecting FACTORY or OBJECT ]) AT_DATA([prog3.cob], [ IDENTIFICATION DIVISION. CLASS-ID. MyFirstClass. END CLASS MyClass. + + INTERFACE-ID. MyFirstInterface. + END INTERFACE MyInterface. ]) AT_CHECK([$COMPILE_ONLY prog3.cob], [1], [], [prog3.cob:3: error: object-oriented COBOL is not supported prog3.cob:4: error: END CLASS 'MyClass' is different from CLASS-ID 'MyFirstClass' +prog3.cob:6: error: object-oriented COBOL (INTERFACE) is not supported +prog3.cob:7: error: END INTERFACE 'MyInterface' is different from INTERFACE-ID 'MyFirstInterface' ]) AT_CLEANUP @@ -93,8 +98,8 @@ AT_DATA([prog.cob], [ AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], [prog.cob:3: error: object-oriented COBOL is not supported -prog.cob:6: error: redefinition of class ID 'MyClass' prog.cob:6: error: object-oriented COBOL is not supported +prog.cob:6: error: redefinition of class ID 'MyClass' ]) AT_CLEANUP @@ -109,16 +114,29 @@ AT_DATA([prog.cob], [ CLASS-ID. DematAccount. END CLASS DematAccount. - + CLASS-ID. SavingsAccount INHERITS FROM Account. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS Account. END CLASS SavingsAccount. *> Skips optional FROM keyword for INHERITS attribute CLASS-ID. MinorSavingsAccount INHERITS SavingsAccount. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS SavingsAccount. END CLASS MinorSavingsAccount. CLASS-ID. MultiPurposeAccount INHERITS FROM Account DematAccount. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS Account + CLASS DematAccount. END CLASS MultiPurposeAccount. CLASS-ID. MyAccount USING startingBalance. @@ -129,9 +147,9 @@ AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], [prog.cob:3: error: object-oriented COBOL is not supported prog.cob:6: error: object-oriented COBOL is not supported prog.cob:9: error: object-oriented COBOL is not supported -prog.cob:13: error: object-oriented COBOL is not supported -prog.cob:16: error: object-oriented COBOL is not supported -prog.cob:20: error: object-oriented COBOL is not supported +prog.cob:17: error: object-oriented COBOL is not supported +prog.cob:24: error: object-oriented COBOL is not supported +prog.cob:33: error: object-oriented COBOL is not supported ]) AT_CLEANUP @@ -143,18 +161,26 @@ AT_DATA([prog.cob], [ IDENTIFICATION DIVISION. CLASS-ID. MySuperClass. END CLASS MySuperClass. - - CLASS-ID. MyFirstClass INHERITS + + CLASS-ID. MyFirstClass INHERITS FROM MySuperClass IS FINAL. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS MySuperClass. END CLASS MyFirstClass. - CLASS-ID. MySecondClass AS "MySecondClass" + CLASS-ID. MySecondClass AS "MySecondClass" IS FINAL. END CLASS MySecondClass. - CLASS-ID. MyThirdClass + CLASS-ID. MyThirdClass INHERITS FROM MySuperClass USING param-name. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS MySuperClass. END CLASS MyThirdClass. *> Skips optional IS keyword for FINAL attribute @@ -166,9 +192,9 @@ AT_DATA([prog.cob], [ AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], [prog.cob:3: error: object-oriented COBOL is not supported prog.cob:6: error: object-oriented COBOL is not supported -prog.cob:10: error: object-oriented COBOL is not supported -prog.cob:15: error: object-oriented COBOL is not supported -prog.cob:20: error: object-oriented COBOL is not supported +prog.cob:14: error: object-oriented COBOL is not supported +prog.cob:18: error: object-oriented COBOL is not supported +prog.cob:28: error: object-oriented COBOL is not supported ]) AT_CLEANUP @@ -184,33 +210,51 @@ AT_DATA([prog.cob], [ CLASS-ID. DematAccount INHERITS Account ABSTRACT IS PUBLIC. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS Account. END CLASS DematAccount. - - CLASS-ID. SavingsAccount + + CLASS-ID. SavingsAccount INHERITS FROM Account FINAL. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS Account. END CLASS SavingsAccount. CLASS-ID. MinorSavingsAccount INHERITS SavingsAccount IS INTERNAL. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS SavingsAccount. END CLASS MinorSavingsAccount. - CLASS-ID. MultiPurposeAccount + CLASS-ID. MultiPurposeAccount INHERITS Account DematAccount PARTIAL. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS Account + CLASS DematAccount. END CLASS MultiPurposeAccount. ]) AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], [prog.cob:3: error: object-oriented COBOL is not supported prog.cob:6: error: object-oriented COBOL is not supported -prog.cob:12: error: object-oriented COBOL is not supported -prog.cob:17: error: object-oriented COBOL is not supported -prog.cob:22: error: object-oriented COBOL is not supported +prog.cob:15: error: object-oriented COBOL is not supported +prog.cob:24: error: object-oriented COBOL is not supported +prog.cob:33: error: object-oriented COBOL is not supported ]) AT_CLEANUP + AT_SETUP([CLASS-ID Attribute Error Check]) AT_KEYWORDS([OOP]) @@ -224,18 +268,31 @@ AT_DATA([prog.cob], [ ABSTRACT IS PUBLIC INTERNAL. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS Account. END CLASS DematAccount. - - CLASS-ID. SavingsAccount + + CLASS-ID. SavingsAccount INHERITS FROM Account FINAL IS ABSTRACT. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS Account. END CLASS SavingsAccount. - CLASS-ID. MultiPurposeAccount + CLASS-ID. MultiPurposeAccount INHERITS Account DematAccount PARTIAL IS PARTIAL. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS Account + CLASS DematAccount. END CLASS MultiPurposeAccount. ]) @@ -244,9 +301,515 @@ AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], prog.cob:4: error: duplicate FINAL clause prog.cob:7: error: object-oriented COBOL is not supported prog.cob:10: error: cannot specify both INTERNAL and PUBLIC -prog.cob:14: error: object-oriented COBOL is not supported -prog.cob:16: error: cannot specify both FINAL and ABSTRACT -prog.cob:20: error: object-oriented COBOL is not supported -prog.cob:22: error: duplicate PARTIAL clause +prog.cob:17: error: object-oriented COBOL is not supported +prog.cob:20: error: cannot specify both FINAL and ABSTRACT +prog.cob:27: error: object-oriented COBOL is not supported +prog.cob:30: error: duplicate PARTIAL clause +]) +AT_CLEANUP + + +AT_SETUP([INTERFACE-ID syntax check]) +AT_KEYWORDS([OOP]) + +AT_DATA([prog.cob], [ + IDENTIFICATION DIVISION. + + INTERFACE-ID. Account. + END INTERFACE Account. + + INTERFACE-ID. DematAccount + INHERITS Account + USING param-name. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + INTERFACE Account. + END INTERFACE DematAccount. +]) + +AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], +[prog.cob:4: error: object-oriented COBOL (INTERFACE) is not supported +prog.cob:7: error: object-oriented COBOL (INTERFACE) is not supported +]) +AT_CLEANUP + + +AT_SETUP([CLASS specifier in REPOSITORY paragraph]) +AT_KEYWORDS([OOP]) + +AT_DATA([prog.cob], [ + IDENTIFICATION DIVISION. + + CLASS-ID. Account IS FINAL. + END CLASS Account. + + CLASS-ID. SavingsAccount + INHERITS ACCOUNT + IS FINAL. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS Account AS "Account". + END CLASS SavingsAccount. +]) + +AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], +[prog.cob:4: error: object-oriented COBOL is not supported +prog.cob:7: error: object-oriented COBOL is not supported +]) +AT_CLEANUP + + +AT_SETUP([CLASS-ID and INTERFACE-ID Syntax Checks]) +AT_KEYWORDS([OOP]) + +AT_DATA([prog1.cob], [ + IDENTIFICATION DIVISION. + INTERFACE-ID. MyFactoryInterface. + END INTERFACE MyFactoryInterface. + + INTERFACE-ID. MyInterface. + END INTERFACE MyInterface. + + CLASS-ID. MyBaseClass. + FACTORY. + IMPLEMENTS MyFactoryInterface. + END FACTORY. + OBJECT. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 data-name PIC 9(2). + PROCEDURE DIVISION. + METHOD-ID. MyMethod IS FINAL. + END METHOD MyMethod. + + METHOD-ID. GET PROPERTY data-name. + END METHOD. + + METHOD-ID. SET PROPERTY data-name. + END METHOD. + END OBJECT. + END CLASS MyBaseClass. + + CLASS-ID. MyDerivedClass + INHERITS FROM MyBaseClass + MyBaseClass + MyUnknownClass + MyDerivedClass. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS MyBaseClass AS "MyKnownClass" + INTERFACE MyInterface. + FACTORY. + END FACTORY. + END CLASS MyDerivedClass. +]) + +AT_CHECK([$COMPILE_ONLY prog1.cob], [1], [], +[prog1.cob:3: error: object-oriented COBOL (INTERFACE) is not supported +prog1.cob:6: error: object-oriented COBOL (INTERFACE) is not supported +prog1.cob:9: error: object-oriented COBOL is not supported +prog1.cob:29: error: object-oriented COBOL is not supported +prog1.cob:37: warning: no definition/prototype seen for CLASS with external name 'MyKnownClass' +prog1.cob:31: error: duplicate parent CLASS 'MyBaseClass' +prog1.cob:30: note: 'MyBaseClass' defined here +prog1.cob:32: error: inherited CLASS 'MyUnknownClass' not found in REPOSITORY paragraph +prog1.cob:33: error: cyclically inheriting CLASS 'MyDerivedClass' +prog1.cob:29: note: 'MyDerivedClass' defined here +prog1.cob:33: error: inherited CLASS 'MyDerivedClass' not found in REPOSITORY paragraph +prog1.cob:31: error: duplicate parent CLASS 'MyBaseClass' +prog1.cob:30: note: 'MyBaseClass' defined here +prog1.cob:32: error: inherited CLASS 'MyUnknownClass' not found in REPOSITORY paragraph +prog1.cob:33: error: cyclically inheriting CLASS 'MyDerivedClass' +prog1.cob:29: note: 'MyDerivedClass' defined here +prog1.cob:33: error: inherited CLASS 'MyDerivedClass' not found in REPOSITORY paragraph +]) + +AT_DATA([prog2.cob], [ + IDENTIFICATION DIVISION. + INTERFACE-ID. MyInterface. + END INTERFACE MyInterface. + + INTERFACE-ID. MyBaseInterface. + END INTERFACE MyBaseInterface. + + INTERFACE-ID. MyDerivedInterface + INHERITS FROM MyBaseInterface + MyBaseInterface + MyUnknownInterface + MyDerivedInterface. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + INTERFACE MyBaseInterface AS "MyKnownInterface" + EXPANDS MyInterface + USING dummy-param. + END INTERFACE MyDerivedInterface. +]) +AT_CHECK([$COMPILE_ONLY prog2.cob], [1], [], +[prog2.cob:3: error: object-oriented COBOL (INTERFACE) is not supported +prog2.cob:6: error: object-oriented COBOL (INTERFACE) is not supported +prog2.cob:9: error: object-oriented COBOL (INTERFACE) is not supported +prog2.cob:17: warning: no definition/prototype seen for INTERFACE with external name 'MyKnownInterface' +prog2.cob:11: error: duplicate parent INTERFACE 'MyBaseInterface' +prog2.cob:10: note: 'MyBaseInterface' defined here +prog2.cob:12: error: inherited INTERFACE 'MyUnknownInterface' not found in REPOSITORY paragraph +prog2.cob:13: error: cyclically inheriting INTERFACE 'MyDerivedInterface' +prog2.cob:9: note: 'MyDerivedInterface' defined here +prog2.cob:13: error: inherited INTERFACE 'MyDerivedInterface' not found in REPOSITORY paragraph ]) + +AT_CLEANUP + + +AT_SETUP([INVOKE statement]) +AT_KEYWORDS([OOP]) + +AT_DATA([prog.cob], [ + IDENTIFICATION DIVISION. + INTERFACE-ID. MyFactoryInterface. + END INTERFACE MyFactoryInterface. + + CLASS-ID. MyBaseClass. + FACTORY. + IMPLEMENTS MyFactoryInterface. + PROCEDURE DIVISION. + METHOD-ID. MyMethod IS FINAL. + PROCEDURE DIVISION. + DISPLAY "Hello, world!". + END METHOD MyMethod. + END FACTORY. + END CLASS MyBaseClass. + + PROGRAM-ID. prog. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS MyBaseClass AS "MyClass". + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 an-object USAGE OBJECT REFERENCE MyBaseClass. + 01 a-factory USAGE OBJECT REFERENCE FACTORY OF ACTIVE-CLASS. + + PROCEDURE DIVISION. + INVOKE MyBaseClass "MyMethod". + INVOKE an-object "MyMethod". + INVOKE a-factory "StaticMethod". + END PROGRAM prog. +]) + +AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], +[prog.cob:3: error: object-oriented COBOL (INTERFACE) is not supported +prog.cob:6: error: object-oriented COBOL is not supported +prog.cob:21: warning: no definition/prototype seen for CLASS with external name 'MyClass' +]) +AT_CLEANUP + + +AT_SETUP([Simple OO Example (Accounts)]) +AT_KEYWORDS([OOP]) + +AT_DATA([prog.cob], [ + IDENTIFICATION DIVISION. + CLASS-ID. Account INHERITS Base. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS Base. + + FACTORY. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 number-of-accounts PIC 9(5) VALUE ZERO. + PROCEDURE DIVISION. + METHOD-ID. newAccount. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 an-object USAGE IS OBJECT REFERENCE ACTIVE-CLASS. + PROCEDURE DIVISION RETURNING an-object. + begin-here. + INVOKE SELF "new" RETURNING an-object. + INVOKE an-object "initializeAccount" + USING BY CONTENT number-of-accounts. + GOBACK. + END METHOD newAccount. + METHOD-ID. addAccount. + PROCEDURE DIVISION. + method-start. + ADD 1 TO number-of-accounts. + GOBACK. + END METHOD addAccount. + METHOD-ID. removeAccount. + PROCEDURE DIVISION. + main-entry. + SUBTRACT 1 FROM number-of-accounts. + GOBACK. + END METHOD removeAccount. + END FACTORY. + + OBJECT. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 account-balance PIC S9(9)V99. + 01 account-number PIC X(9). + 01 the-date PIC 9(8). + PROCEDURE DIVISION. + METHOD-ID. displayUI. + DATA DIVISION. + LOCAL-STORAGE SECTION. + 01 in-data. + 03 action-type PIC X. + 03 in-amount PIC S9(9)V99. + 03 in-wrk PIC X(12). + PROCEDURE DIVISION. + + get-amount. + DISPLAY "Enter amount 9(9).99" + ACCEPT in-wrk + COMPUTE in-amount = FUNCTION NUMVAL (in-wrk) + . + END METHOD displayUI. + METHOD-ID. balance. + DATA DIVISION. + LOCAL-STORAGE SECTION. + 01 display-balance PIC $ZZZ,ZZZ,ZZ9.99B-. + PROCEDURE DIVISION. + disp-balance. + MOVE account-balance to display-balance + DISPLAY "Your Account Balance is:" display-balance + GOBACK. + END METHOD balance. + METHOD-ID. deposit. + DATA DIVISION. + LINKAGE SECTION. + 01 in-deposit PIC S9(9)V99. + PROCEDURE DIVISION USING in-deposit. + make-deposit. + ADD in-deposit TO account-balance + GOBACK. + END METHOD deposit. + METHOD-ID. withdraw. + DATA DIVISION. + LINKAGE SECTION. + 01 in-withdraw PIC S9(9)V99. + PROCEDURE DIVISION USING in-withdraw. + withdraw-start. + IF account-balance >= in-withdraw + SUBTRACT in-withdraw FROM account-balance + ELSE + DISPLAY "Your Balance is Inadequate" + END-IF + GOBACK. + END METHOD withdraw. + METHOD-ID. initializeAccount. + DATA DIVISION. + LINKAGE SECTION. + 01 new-account-number PIC 9(5). + PROCEDURE DIVISION USING new-account-number. + Begin-initialization. + MOVE ZERO TO account-balance + MOVE new-account-number TO account-number + MOVE FUNCTION CURRENT-DATE (1: 8) TO the-date + GOBACK. + END METHOD initializeAccount. + END OBJECT. + END CLASS Account. +]) + +AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], +[prog.cob:3: error: object-oriented COBOL is not supported +prog.cob:7: warning: no definition/prototype seen for CLASS 'Base' +prog.cob:18: error: RETURNING item is not defined in LINKAGE SECTION +prog.cob: in paragraph 'begin-here': +prog.cob:22: error: 'number-of-accounts' is not defined +prog.cob: in paragraph 'method-start': +prog.cob:28: error: 'number-of-accounts' is not defined +prog.cob: in paragraph 'main-entry': +prog.cob:34: error: 'number-of-accounts' is not defined +prog.cob: in paragraph 'disp-balance': +prog.cob:67: error: 'account-balance' is not defined +prog.cob: in paragraph 'make-deposit': +prog.cob:77: error: 'account-balance' is not defined +prog.cob: in paragraph 'withdraw-start': +prog.cob:86: error: 'account-balance' is not defined +prog.cob: in paragraph 'Begin-initialization': +prog.cob:99: error: 'account-balance' is not defined +prog.cob:100: error: 'account-number' is not defined +prog.cob:101: error: 'the-date' is not defined +]) +AT_CLEANUP + + +AT_SETUP([Inline method invocation expression]) +AT_KEYWORDS([OOP]) + +AT_DATA([prog.cob], [ + IDENTIFICATION DIVISION. + CLASS-ID. MyBaseClass AS "MyClass". + FACTORY. + PROCEDURE DIVISION. + METHOD-ID. MyMethod IS FINAL. + DATA DIVISION. + LINKAGE SECTION. + 01 VAR-IN PIC 9(2). + 01 VAR-OUT PIC 9(2). + PROCEDURE DIVISION USING VAR-IN + RETURNING VAR-OUT. + MOVE VAR-IN TO VAR-OUT. + DISPLAY "Hello, world!". + END METHOD MyMethod. + END FACTORY. + OBJECT. + PROCEDURE DIVISION. + METHOD-ID. SayHello. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS MyBaseClass AS "MyClass". + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 an-object USAGE OBJECT REFERENCE MyBaseClass. + 01 a-var PIC 9(2). + PROCEDURE DIVISION. + DISPLAY an-object :: "MyMethod" (10). + DISPLAY an-object :: "MyMethod" (). + DISPLAY an-object :: "MyMethod" (10 + 2). + DISPLAY an-object :: "MyMethod" (10 + 2, 42). + DISPLAY an-object :: "MyMethod" (OMITTED). + DISPLAY an-object :: "MyMethod" (OMITTED, 42). + MOVE 98 TO a-var. + DISPLAY an-object :: "MyMethod" (a-var). + DISPLAY SELF. + DISPLAY SELF :: "MyMethod" (a-var). + INVOKE an-object "MyMethod" USING SUPER. + END METHOD SayHello. + END OBJECT. + END CLASS MyBaseClass. + + PROGRAM-ID. prog. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS MyBaseClass AS "MyClass". + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 an-object USAGE OBJECT REFERENCE MyBaseClass. + 01 a-var PIC 9(2). + + PROCEDURE DIVISION. + DISPLAY an-object :: "MyMethod" (10). + DISPLAY an-object :: "MyMethod" (10 + 2). + MOVE 98 TO a-var. + DISPLAY an-object :: "MyMethod" (a-var). + DISPLAY an-object :: "SayHello". + + INVOKE an-object "SayHello" USING 1. + INVOKE an-object "MyMethod" USING SUPER. + + MOVE SELF TO an-object. + MOVE SUPER TO an-object. + END PROGRAM prog. +]) + +AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], +[prog.cob:3: error: object-oriented COBOL is not supported +prog.cob:30: warning: argument #1 is not optional +prog.cob:32: warning: expecting up to 1 arguments, but found 2 +prog.cob:33: warning: argument #1 is not optional +prog.cob:34: warning: argument #1 is not optional +prog.cob:34: warning: expecting up to 1 arguments, but found 2 +prog.cob:37: error: 'MyBaseClass' is an invalid type for DISPLAY operand +prog.cob:39: warning: expecting a RETURNING item, but none provided +prog.cob:59: warning: invalid inline invocation of a method with no RETURNING +prog.cob:61: warning: expecting up to 0 arguments, but found 1 +prog.cob:62: error: use of SUPER outside of METHOD definition +prog.cob:62: warning: expecting a RETURNING item, but none provided +prog.cob:64: error: use of SELF outside of METHOD definition +prog.cob:65: error: use of SUPER outside of METHOD definition +]) +AT_CLEANUP + + +AT_SETUP([SUPER in multiple inheritance context]) +AT_KEYWORDS([OOP]) + +AT_DATA([prog.cob], [ + CLASS-ID. A. + OBJECT. + PROCEDURE DIVISION. + METHOD-ID. M. + END METHOD M. + END OBJECT. + END CLASS A. + + CLASS-ID. B. + OBJECT. + PROCEDURE DIVISION. + METHOD-ID. M. + END METHOD M. + END OBJECT. + END CLASS B. + + CLASS-ID. C INHERITS A B. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS A + CLASS B. + OBJECT. + PROCEDURE DIVISION. + METHOD-ID. M. + PROCEDURE DIVISION. + INVOKE SUPER "M" + GOBACK. + END METHOD M. + END OBJECT. + END CLASS C. +]) +AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], +[prog.cob:2: error: object-oriented COBOL is not supported +prog.cob:10: error: object-oriented COBOL is not supported +prog.cob:18: error: object-oriented COBOL is not supported +prog.cob:28: warning: use of SUPER in CLASS or INTERFACE with multiple inheritance may be ambiguous +]) + +AT_CLEANUP + + +AT_SETUP([Wrong CLASS prototype]) +AT_KEYWORDS([OOP]) + +AT_DATA([prog.cob], [ + FUNCTION-ID. fun. + DATA DIVISION. + LINKAGE SECTION. + 77 X PIC 9. + PROCEDURE DIVISION RETURNING X. + MOVE 0 TO X + GOBACK. + END FUNCTION fun. + + PROGRAM-ID. prog. + ENVIRONMENT DIVISION. + CONFIGURATION SECTION. + REPOSITORY. + CLASS C AS "fun". + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 O USAGE OBJECT REFERENCE C. + PROCEDURE DIVISION. + INVOKE C "MyMethod". + INVOKE O "MyMethod". + END PROGRAM prog. +]) + +AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], +[prog.cob:15: error: CLASS REPOSITORY entry for 'fun' does not match its definition +prog.cob:15: note: 'fun' defined as a FUNCTION here +prog.cob:20: error: CLASS or INTERFACE expected (got FUNCTION 'fun') +prog.cob:21: error: CLASS or INTERFACE expected (got FUNCTION 'fun') +]) + AT_CLEANUP diff --git a/tests/testsuite.src/syn_screen.at b/tests/testsuite.src/syn_screen.at index ec3c4de5a..1221dba88 100644 --- a/tests/testsuite.src/syn_screen.at +++ b/tests/testsuite.src/syn_screen.at @@ -808,8 +808,8 @@ AT_DATA([prog.cob], [ AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], [prog.cob:10: error: 'LIN' is not defined prog.cob:10: error: syntax error, unexpected COL -prog.cob:11: error: syntax error, unexpected COL, expecting Literal or [)] or Identifier -prog.cob:12: error: syntax error, unexpected COL, expecting Literal or [)] or Identifier +prog.cob:11: error: syntax error, unexpected COL +prog.cob:12: error: syntax error, unexpected COL prog.cob:19: error: syntax error, unexpected COL prog.cob:20: error: syntax error, unexpected COL ])