diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1edad6f3..2ec7767b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -25,8 +25,6 @@ on: - 'master' pull_request: - branches: - - 'master' jobs: ubuntu-build-test: diff --git a/src/main/java/com/eprosima/fastcdr/idl/context/Context.java b/src/main/java/com/eprosima/fastcdr/idl/context/Context.java index 58f1c4a4..3c048fb4 100644 --- a/src/main/java/com/eprosima/fastcdr/idl/context/Context.java +++ b/src/main/java/com/eprosima/fastcdr/idl/context/Context.java @@ -41,8 +41,6 @@ public interface Context public boolean isGenerateTypeObject(); - public boolean isGenerateTypesC(); - public boolean isGenerateTypesROS2(); public boolean isCdr(); diff --git a/src/main/java/com/eprosima/fastcdr/idl/templates/TypesHeader.stg b/src/main/java/com/eprosima/fastcdr/idl/templates/TypesHeader.stg index 72394ffd..b6e244d4 100644 --- a/src/main/java/com/eprosima/fastcdr/idl/templates/TypesHeader.stg +++ b/src/main/java/com/eprosima/fastcdr/idl/templates/TypesHeader.stg @@ -118,10 +118,6 @@ $definition_list$ } // namespace $module.name$ >> -definition_list(definitions) ::= << -$definitions; separator="\n"$ ->> - annotation(ctx, annotation) ::= << namespace $annotation.name$ { $annotation.enums : { enum | $enum_type(ctx=ctx, parent=annotation, enum=enum)$}; separator="\n"$ @@ -146,27 +142,6 @@ public: }; >> -export_list(exports) ::= << -$exports; separator="\n"$ ->> - -exception(ctx, parent, exception) ::= <<>> - -operation(ctx, parent, operation, param_list, operation_type) ::= << - -$operation_type$ -$param_list$ - ->> - -param_list(parameters) ::= <<>> - -param(parameter, parameter_type) ::= << - -$parameter_type$ - ->> - const_decl(ctx, parent, const, const_type) ::= <<$const_type$$if(ctx.inScopedFile)$$if(const.parent)$$if(const.parent.isInterface)$static $endif$$endif$const $const.typeCode.cppTypename$ $const.name$$if(!const.parent)$ = $const.value$$elseif(!const.parent.isInterface)$ = $const.value$$elseif(!const.typeCode.isType_5)$$if(!const.typeCode.isType_6)$ = $const.value$$endif$$endif$;$endif$>> typedef_decl(ctx, parent, typedefs, typedefs_type, declarator_type) ::= << @@ -258,13 +233,6 @@ private: }; >> -member_type(ctx, member, type_member, declarators) ::= << - -$type_member$ -$declarators$ - ->> - union_type(ctx, parent, union, extensions, switch_type) ::= << $switch_type$ /*! @@ -358,13 +326,6 @@ private: }; >> -element_type(ctx, element, type_element, declarator) ::= << - -$type_element$ -$declarator$ - ->> - bitset_type(ctx, parent, bitset, extensions) ::= << /*! * @brief This class represents the structure $bitset.name$ defined by the user in the IDL file. @@ -471,25 +432,6 @@ class $type.name$; >> -sequence_type(ctx, sequence, type_sequence) ::= << - -$type_sequence$ - ->> - -map_type(ctx, map, key_type, value_type) ::= << - -$key_type$ -$value_type$ - ->> - -string_type(ctx, string) ::= <<>> - -wide_string_type(ctx, wstring) ::= <<>> - -array_declarator(ctx, array, array_type) ::= <<>> - /***** Utils *****/ public_struct_inheritances(parent) ::= <<$parent.scopedname$>> @@ -801,3 +743,17 @@ private: void free_memory(); }; >> + +//{ Fast DDS-Gen extensions +module_conversion(ctx, parent, modules, definition_list) ::= << +$modules : { module | +namespace $module.name$ { +}; separator="\n"$ + +$definition_list$ + +$reverse(modules) : { module | +\} // namespace $module.name$ +}; separator="\n"$ +>> +//} diff --git a/src/main/java/com/eprosima/fastcdr/idl/templates/TypesHeaderv1.stg b/src/main/java/com/eprosima/fastcdr/idl/templates/TypesHeaderv1.stg index 95294144..3069317c 100644 --- a/src/main/java/com/eprosima/fastcdr/idl/templates/TypesHeaderv1.stg +++ b/src/main/java/com/eprosima/fastcdr/idl/templates/TypesHeaderv1.stg @@ -103,17 +103,12 @@ $if(ctx.cdr_both)$ $endif$ >> -// TODO name -> module module(ctx, parent, module, definition_list) ::= << namespace $module.name$ { $definition_list$ } // namespace $module.name$ >> -definition_list(definitions) ::= << -$definitions; separator="\n"$ ->> - annotation(ctx, annotation) ::= << namespace $annotation.name$ { $annotation.enums : { enum | $enum_type(ctx=ctx, parent=annotation, enum=enum)$}; separator="\n"$ @@ -138,10 +133,6 @@ public: }; >> -export_list(exports) ::= << -$exports; separator="\n"$ ->> - exception(ctx, parent, exception) ::= << $if(ctx.printexception)$ /*! @@ -210,10 +201,6 @@ virtual $paramRetType(operation.rettype)$ $operation.name$($paramDeclarations(pa $endif$ >> -param_list(parameters) ::= <<>> - -param(parameter) ::= <<>> - const_decl(ctx, parent, const, const_type) ::= << $ctx.setCdrv1Templates$ $const_type$ @@ -556,39 +543,6 @@ enum $bitmask.name$Bits$bitmask.boundType$ typedef $bitmask.castingType$ $bitmask.name$; >> -sequence_type(ctx, sequence, type_sequence) ::= << - -$type_sequence$ - ->> - -map_type(ctx, map, key_type, value_type) ::= << - -$key_type$ -$value_type$ - ->> - -string_type(ctx, string) ::= <<>> - -wide_string_type(ctx, wstring) ::= <<>> - -array_declarator(ctx, array, array_type) ::= <<>> - -member_type(ctx, member, type_member, declarators) ::= << - -$type_member$ -$declarators$ - ->> - -element_type(ctx, element, type_element, declarator) ::= << - -$type_element$ -$declarator$ - ->> - /***** Utils *****/ public_struct_inheritances(parent) ::= <<$parent.scopedname$>> @@ -950,3 +904,17 @@ private: void free_memory(); }; >> + +//{ Fast DDS-Gen extensions +module_conversion(ctx, parent, modules, definition_list) ::= << +$modules : { module | +namespace $module.name$ { +}; separator="\n"$ + +$definition_list$ + +$reverse(modules) : { module | +\} // namespace $module.name$ +}; separator="\n"$ +>> +//} diff --git a/src/main/java/com/eprosima/fastcdr/idl/templates/TypesSource.stg b/src/main/java/com/eprosima/fastcdr/idl/templates/TypesSource.stg index 930b1aeb..a17daaff 100644 --- a/src/main/java/com/eprosima/fastcdr/idl/templates/TypesSource.stg +++ b/src/main/java/com/eprosima/fastcdr/idl/templates/TypesSource.stg @@ -77,39 +77,6 @@ $definition_list$ } // namespace $module.name$ >> -definition_list(definitions) ::= << -$definitions; separator="\n"$ - ->> - -annotation(ctx, annotation) ::= <<>> - -interface(ctx, parent, interface, export_list) ::= << -$export_list$ ->> - -export_list(exports) ::= << -$exports; separator="\n"$ - ->> - -exception(ctx, parent, exception) ::= <<>> - -operation(ctx, parent, operation, param_list, operation_type) ::= << - -$operation_type$ -$param_list$ - ->> - -param_list(parameters) ::= <<>> - -param(parameter, parameter_type) ::= << - -$parameter_type$ - ->> - const_decl(ctx, parent, const, const_type) ::= << $const_type$ $if(const.parent)$ @@ -123,8 +90,6 @@ $endif$ $endif$ >> -fwd_decl(ctx, parent, type) ::= <<>> - typedef_decl(ctx, parent, typedefs, typedefs_type, declarator_type) ::= << $declarator_type$ $typedefs_type$ @@ -257,13 +222,6 @@ $struct.members:{ member | $public_member_declaration(class=struct.name, member= $extensions : { extension | $extension$}; separator="\n"$ >> -member_type(ctx, member, type_member, declarators) ::= << - -$type_member$ -$declarators$ - ->> - bitset_type(ctx, parent, bitset) ::= << $bitset.name$::$bitset.name$()$if(bitset.inheritance)$ : $bitset_inherit_default_init(bitset.inheritance)$$endif$ @@ -571,36 +529,6 @@ void $union.name$::deserialize( $endif$ >> -element_type(ctx, element, type_element, declarator) ::= << - -$type_element$ -$declarator$ - ->> - -enum_type(ctx, parent, enum) ::= <<>> - -bitmask_type(ctx, parent, bitmask) ::= <<>> - -sequence_type(ctx, sequence, type_sequence) ::= << - -$type_sequence$ - ->> - -map_type(ctx, map, key_type, value_type) ::= << - -$key_type$ -$value_type$ - ->> - -string_type(ctx, string) ::= <<>> - -wide_string_type(ctx, wstring) ::= <<>> - -array_declarator(ctx, array, array_type) ::= <<>> - /***** Utils *****/ public_member_declaration(class, member) ::= << @@ -1411,3 +1339,17 @@ void $scopedtypename$::free_memory() $endif$ >> + +//{ Fast DDS-Gen extensions +module_conversion(ctx, parent, modules, definition_list) ::= << +$modules : { module | +namespace $module.name$ { +}; separator="\n"$ + +$definition_list$ + +$reverse(modules) : { module | +\} // namespace $module.name$ +}; separator="\n"$ +>> +//} diff --git a/src/main/java/com/eprosima/fastcdr/idl/templates/TypesSourcev1.stg b/src/main/java/com/eprosima/fastcdr/idl/templates/TypesSourcev1.stg index 79ee4010..59f2058b 100644 --- a/src/main/java/com/eprosima/fastcdr/idl/templates/TypesSourcev1.stg +++ b/src/main/java/com/eprosima/fastcdr/idl/templates/TypesSourcev1.stg @@ -126,22 +126,6 @@ $definition_list$ } // namespace $module.name$ >> -definition_list(definitions) ::= << -$definitions; separator="\n"$ - ->> - -annotation(ctx, annotation) ::= <<>> - -interface(ctx, parent, interface, export_list) ::= << -$export_list$ ->> - -export_list(exports) ::= << -$exports; separator="\n"$ - ->> - exception(ctx, parent, exception) ::= << $if(ctx.printexception)$ $exception.name$::$exception.name$() @@ -238,12 +222,6 @@ $endif$ $endif$ >> -operation(ctx, parent, operation, param_list) ::= <<>> - -param_list(parameters) ::= <<>> - -param(parameter) ::= <<>> - const_decl(ctx, parent, const, const_type) ::= << $ctx.setCdrv1Templates$ $const_type$ @@ -259,8 +237,6 @@ $endif$ $ctx.unsetCdrv1Templates$ >> -fwd_decl(ctx, parent, type) ::= <<>> - typedef_decl(ctx, parent, typedefs, typedefs_type, declarator_type) ::= << $ctx.setCdrv1Templates$ $declarator_type$ @@ -898,43 +874,6 @@ $endif$ $ctx.unsetCdrv1Templates$ >> -enum_type(ctx, parent, enum) ::= <<>> - -bitmask_type(ctx, parent, bitmask) ::= <<>> - -sequence_type(ctx, sequence, type_sequence) ::= << - -$type_sequence$ - ->> - -map_type(ctx, map, key_type, value_type) ::= << - -$key_type$ -$value_type$ - ->> - -string_type(ctx, string) ::= <<>> - -wide_string_type(ctx, wstring) ::= <<>> - -array_declarator(ctx, array, array_type) ::= <<>> - -member_type(ctx, member, type_member, declarators) ::= << - -$type_member$ -$declarators$ - ->> - -element_type(ctx, element, type_element, declarator) ::= << - -$type_element$ -$declarator$ - ->> - /***** Utils *****/ public_member_declaration(class, member) ::= << @@ -2339,3 +2278,17 @@ member_array_default_cstring_init(ctx, name, loopvar, dims) ::= <<$if(rest(dims) indexName(name, loopvar) ::= <<$name$[$loopvar$]>> memberName(name) ::= <> + +//{ Fast DDS-Gen extensions +module_conversion(ctx, parent, modules, definition_list) ::= << +$modules : { module | +namespace $module.name$ { +}; separator="\n"$ + +$definition_list$ + +$reverse(modules) : { module | +\} // namespace $module.name$ +}; separator="\n"$ +>> +//} diff --git a/src/main/java/com/eprosima/fastcdr/idl/templates/TypesSwigInterface.stg b/src/main/java/com/eprosima/fastcdr/idl/templates/TypesSwigInterface.stg index 7757141a..36cfadca 100644 --- a/src/main/java/com/eprosima/fastcdr/idl/templates/TypesSwigInterface.stg +++ b/src/main/java/com/eprosima/fastcdr/idl/templates/TypesSwigInterface.stg @@ -76,15 +76,6 @@ $endif$ $"\n"$ >> -module(ctx, parent, module, definition_list) ::= << -$definition_list$ ->> - -definition_list(definitions) ::= << -$definitions; separator="\n"$ - ->> - fast_macro_declarations() ::= << // Macro declarations // Any macro used on the Fast DDS header files will give an error if it is not redefined here @@ -123,13 +114,6 @@ $struct.members : { member | $member_getters(struct_name=struct.scopedname, memb >> -member_type(ctx, member, type_member, declarators) ::= << - -$type_member$ -$declarators$ - ->> - template_sequence_name(typecode) ::= <% $if(typecode.isSequenceType)$ $template_sequence_name(typecode.contentTypeCode)$_vector @@ -226,13 +210,6 @@ $union.members : { member | $member_getters(struct_name=union.name, member=membe >> -element_type(ctx, element, type_element, declarator) ::= << - -$type_element$ -$declarator$ - ->> - bitset_type(ctx, parent, bitset, extensions) ::= << //////////////////////////////////////////////////////// // Binding for class $bitset.name$ @@ -248,48 +225,3 @@ bitset_type(ctx, parent, bitset, extensions) ::= << enum_type(ctx, parent, enum) ::= << %traits_penumn(enum $enum.cppTypename$); >> - -// bitmasks are implemented as enums. Therefore, are ported as constants in the target language -bitmask_type(ctx, parent, bitmask) ::= <<>> - -sequence_type(ctx, sequence, type_sequence) ::= << - -$type_sequence$ - ->> - -map_type(ctx, map, key_type, value_type) ::= << - -$key_type$ -$value_type$ - ->> - -string_type(ctx, string) ::= <<>> - -wide_string_type(ctx, wstring) ::= <<>> - -array_declarator(ctx, array, array_type) ::= <<>> - -const_decl(ctx, parent, const, const_type) ::= << - -$const_type$ - ->> - -annotation(ctx, parent, annotation) ::= <<>> - -typedef_decl(ctx, parent, typedefs, typedefs_type, declarator_type) ::= << - -$declarator_type$ -$typedefs_type$ - ->> - -fwd_decl(ctx, parent, type) ::= <<>> - -annotation(ctx, annotation) ::= <<>> - -interface(ctx, parent, interface, export_list) ::= <<>> - -exception(ctx, parent, exception) ::= <<>> diff --git a/src/main/java/com/eprosima/fastdds/fastddsgen.java b/src/main/java/com/eprosima/fastdds/fastddsgen.java index 5be38b03..75b40873 100644 --- a/src/main/java/com/eprosima/fastdds/fastddsgen.java +++ b/src/main/java/com/eprosima/fastdds/fastddsgen.java @@ -27,8 +27,6 @@ import com.eprosima.idl.parser.grammar.IDLLexer; import com.eprosima.idl.parser.grammar.IDLParser; import com.eprosima.idl.parser.tree.Annotation; -import com.eprosima.idl.parser.tree.AnnotationDeclaration; -import com.eprosima.idl.parser.tree.AnnotationMember; import com.eprosima.idl.parser.tree.Specification; import com.eprosima.idl.parser.typecode.Kind; import com.eprosima.idl.parser.typecode.PrimitiveTypeCode; @@ -122,6 +120,9 @@ public class fastddsgen // Testing private boolean m_test = false; + // Generating internal API + private boolean gen_api_ = false; + // Use to know the programming language public enum LANGUAGE { @@ -161,6 +162,75 @@ public fastddsgen( { m_idlFiles.add(arg); } + else if (arg.equals("-cdr")) + { + if (count < args.length) + { + String cdr_version_str = args[count++]; + if (cdr_version_str.equals(CdrVersion.v1_str)) + { + cdr_version_ = CdrVersion.Select.V1; + } + else if (cdr_version_str.equals(CdrVersion.v2_str)) + { + cdr_version_ = CdrVersion.Select.V2; + } + else if (cdr_version_str.equals(CdrVersion.both_str)) + { + cdr_version_ = CdrVersion.Select.BOTH; + } + else + { + throw new BadArgumentException("CDR version value " + cdr_version_str + " is not valid"); + } + } + else + { + throw new BadArgumentException("No CDR version value after -cdr argument"); + } + } + else if (arg.equals("-cs")) + { + m_case_sensitive = true; + } + else if (arg.equals("-d")) + { + if (count < args.length) + { + m_outputDir = Utils.addFileSeparator(args[count++]); + } + else + { + throw new BadArgumentException("No URL specified after -d argument"); + } + } + else if (arg.equals("-de") || arg.equals("-default_extensibility")) + { + if (count < args.length) + { + String extensibility = args[count++]; + if (extensibility.equals(Annotation.final_str)) + { + TypeCode.default_extensibility = TypeCode.ExtensibilityKind.FINAL; + } + else if (extensibility.equals(Annotation.appendable_str)) + { + TypeCode.default_extensibility = TypeCode.ExtensibilityKind.APPENDABLE; + } + else if (extensibility.equals(Annotation.mutable_str)) + { + TypeCode.default_extensibility = TypeCode.ExtensibilityKind.MUTABLE; + } + else + { + throw new BadArgumentException("Extensibility value " + extensibility + " is not valid"); + } + } + else + { + throw new BadArgumentException("No extensibility value after -default_extensibility argument"); + } + } else if (arg.equals("-example")) { if (count < args.length) @@ -176,6 +246,42 @@ else if (arg.equals("-example")) throw new BadArgumentException("No architecture speficied after -example argument"); } } + else if (arg.equals("-extrastg")) + { + if (count + 1 < args.length) + { + m_customStgOutput.put(args[count++], args[count++]); + } + else + { + throw new BadArgumentException("Missing arguments for -extrastg"); + } + } + else if (arg.equals("-genapi")) + { + gen_api_ = true; + } + else if (arg.equals("-help")) + { + printHelp(); + System.exit(0); + } + else if (arg.equals("-help+")) + { + printEnhacedHelp(); + System.exit(0); + } + else if (arg.equals("-I")) + { + if (count < args.length) + { + m_includePaths.add("-I".concat(args[count++])); + } + else + { + throw new BadArgumentException("No include directory specified after -I argument"); + } + } else if (arg.equals("-language")) { if (count < args.length) @@ -211,6 +317,10 @@ else if (arg.equals("-package")) throw new BadArgumentException("No package after -package argument"); } } + else if (arg.equals("-ppDisable")) + { + m_ppDisable = true; + } else if (arg.equals("-ppPath")) { if (count < args.length) @@ -222,36 +332,14 @@ else if (arg.equals("-ppPath")) throw new BadArgumentException("No URL specified after -ppPath argument"); } } - else if (arg.equals("-extrastg")) - { - if (count + 1 < args.length) - { - m_customStgOutput.put(args[count++], args[count++]); - } - else - { - throw new BadArgumentException("Missing arguments for -extrastg"); - } - } - else if (arg.equals("-ppDisable")) + else if (arg.equals("-python")) { - m_ppDisable = true; + m_python = true; } else if (arg.equals("-replace")) { m_replace = true; } - else if (arg.equals("-d")) - { - if (count < args.length) - { - m_outputDir = Utils.addFileSeparator(args[count++]); - } - else - { - throw new BadArgumentException("No URL specified after -d argument"); - } - } else if (arg.equals("-t")) { if (count < args.length) @@ -263,108 +351,30 @@ else if (arg.equals("-t")) throw new BadArgumentException("No temporary directory specified after -t argument"); } } - else if (arg.equals("-version")) - { - showVersion(); - System.exit(0); - } - else if (arg.equals("-help")) + else if (arg.equals("-test")) { - printHelp(); - System.exit(0); + m_test = true; } - else if (arg.equals("-fusion")) + else if (arg.equals("-typeobject")) { - fusion_ = true; + m_type_object_files = true; } else if (arg.equals("-typeros2")) { m_type_ros2 = true; } - else if (arg.equals("-typeobject")) - { - m_type_object_files = true; - } else if (arg.equals("-typesc")) { m_typesc = true; } - else if (arg.equals("-python")) - { - m_python = true; - } - else if (arg.equals("-test")) - { - m_test = true; - } - else if (arg.equals("-I")) - { - if (count < args.length) - { - m_includePaths.add("-I".concat(args[count++])); - } - else - { - throw new BadArgumentException("No include directory specified after -I argument"); - } - } - else if (arg.equals("-cs")) - { - m_case_sensitive = true; - } - else if (arg.equals("-de") || arg.equals("-default_extensibility")) + else if (arg.equals("-version")) { - if (count < args.length) - { - String extensibility = args[count++]; - if (extensibility.equals(Annotation.final_str)) - { - TypeCode.default_extensibility = TypeCode.ExtensibilityKind.FINAL; - } - else if (extensibility.equals(Annotation.appendable_str)) - { - TypeCode.default_extensibility = TypeCode.ExtensibilityKind.APPENDABLE; - } - else if (extensibility.equals(Annotation.mutable_str)) - { - TypeCode.default_extensibility = TypeCode.ExtensibilityKind.MUTABLE; - } - else - { - throw new BadArgumentException("Extensibility value " + extensibility + " is not valid"); - } - } - else - { - throw new BadArgumentException("No extensibility value after -default_extensibility argument"); - } + showVersion(); + System.exit(0); } - else if (arg.equals("-cdr")) + else if (arg.equals("-fusion")) { - if (count < args.length) - { - String cdr_version_str = args[count++]; - if (cdr_version_str.equals(CdrVersion.v1_str)) - { - cdr_version_ = CdrVersion.Select.V1; - } - else if (cdr_version_str.equals(CdrVersion.v2_str)) - { - cdr_version_ = CdrVersion.Select.V2; - } - else if (cdr_version_str.equals(CdrVersion.both_str)) - { - cdr_version_ = CdrVersion.Select.BOTH; - } - else - { - throw new BadArgumentException("CDR version value " + cdr_version_str + " is not valid"); - } - } - else - { - throw new BadArgumentException("No CDR version value after -cdr argument"); - } + fusion_ = true; } else // TODO: More options: -rpm, -debug { @@ -547,8 +557,19 @@ public static void printHelp() System.out.println(m_appName + " usage:"); System.out.println("\t" + m_appName + " [options] [ ...]"); System.out.println("\twhere the options are:"); - System.out.println("\t\t-help: shows this help"); - System.out.println("\t\t-version: shows the current version of eProsima Fast DDS gen."); + System.out.println("\t\t-cdr : sets the CDR version used to generate types source code."); + System.out.println("\t\t Values:"); + System.out.println("\t\t\t* " + CdrVersion.v1_str); + System.out.println("\t\t\t* " + CdrVersion.v2_str + " (default)"); + System.out.println("\t\t\t* " + CdrVersion.both_str); + System.out.println("\t\t-cs: IDL grammar apply case sensitive matching."); + System.out.println("\t\t-d : sets an output directory for generated files."); + System.out.print("\t\t-default_extensibility | -de : sets the default extensibility for types without"); + System.out.println(" the @extensibility annotation."); + System.out.println("\t\t Values:"); + System.out.println("\t\t\t* " + Annotation.final_str); + System.out.println("\t\t\t* " + Annotation.appendable_str + " (default)"); + System.out.println("\t\t\t* " + Annotation.mutable_str); System.out.println( "\t\t-example : Generates a solution for a specific platform (example: x64Win64VS2019)"); System.out.println("\t\t\tSupported platforms:"); @@ -556,36 +577,31 @@ public static void printHelp() { System.out.println("\t\t\t * " + m_platforms.get(count)); } - //System.out.println("\t\t-language : Programming language (default: C++)."); - System.out.println("\t\t-replace: replaces existing generated files."); - System.out.println("\t\t-ppDisable: disables the preprocessor."); - System.out.println("\t\t-ppPath: specifies the preprocessor path."); System.out.println("\t\t-extrastg