diff options
Diffstat (limited to 'bundles')
72 files changed, 5208 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.ql/.classpath b/bundles/org.eclipse.equinox.p2.ql/.classpath new file mode 100644 index 000000000..2fbb7a23e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.4"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/bundles/org.eclipse.equinox.p2.ql/.project b/bundles/org.eclipse.equinox.p2.ql/.project new file mode 100644 index 000000000..6140e1be9 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/.project @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.equinox.p2.ql</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature> + </natures> +</projectDescription> diff --git a/bundles/org.eclipse.equinox.p2.ql/.settings/org.eclipse.core.resources.prefs b/bundles/org.eclipse.equinox.p2.ql/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..b069b3cf4 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +#Thu Nov 12 08:11:03 CET 2009 +eclipse.preferences.version=1 +encoding//model/p2ql.ecorediag=UTF-8 diff --git a/bundles/org.eclipse.equinox.p2.ql/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.equinox.p2.ql/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..28a744cc1 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,345 @@ +#Fri Nov 20 18:04:34 CET 2009 +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch +org.eclipse.jdt.core.circularClasspath=error +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.4 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.maxProblemPerUnit=1000 +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=error +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=enabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=error +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.3 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=false +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false +org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false +org.eclipse.jdt.core.formatter.comment.indent_root_tags=false +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=80 +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=800 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false +org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error diff --git a/bundles/org.eclipse.equinox.p2.ql/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.equinox.p2.ql/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 000000000..014501b61 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,57 @@ +#Sun Sep 23 11:57:54 EDT 2007 +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_core +formatter_settings_version=11 +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=; +org.eclipse.jdt.ui.ondemandthreshold=3 +org.eclipse.jdt.ui.staticondemandthreshold=3 +org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates/> +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.format_source_code=true +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_variable_declarations_final=true +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=false +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_trailing_whitespaces=false +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=true +sp_cleanup.remove_unnecessary_nls_tags=false +sp_cleanup.remove_unused_imports=false +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true diff --git a/bundles/org.eclipse.equinox.p2.ql/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.ql/META-INF/MANIFEST.MF new file mode 100644 index 000000000..edb4c7d52 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/META-INF/MANIFEST.MF @@ -0,0 +1,22 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.equinox.p2.ql;singleton:=true +Bundle-Version: 1.0.0 +Bundle-ClassPath: . +Bundle-Vendor: %providerName +Bundle-Localization: plugin +Bundle-RequiredExecutionEnvironment: J2SE-1.4, + CDC-1.1/Foundation-1.1 +Bundle-ActivationPolicy: lazy +Import-Package: org.eclipse.equinox.internal.provisional.p2.engine, + org.eclipse.equinox.internal.provisional.p2.metadata, + org.eclipse.equinox.internal.provisional.p2.metadata.query, + org.eclipse.equinox.p2.metadata, + org.eclipse.equinox.p2.metadata.query, + org.eclipse.equinox.p2.repository.artifact, + org.osgi.framework +Export-Package: org.eclipse.equinox.internal.p2.ql, + org.eclipse.equinox.p2.ql +Bundle-Activator: org.eclipse.equinox.internal.p2.ql.QLActivator +Require-Bundle: org.eclipse.equinox.common;bundle-version="3.5.1" diff --git a/bundles/org.eclipse.equinox.p2.ql/about.html b/bundles/org.eclipse.equinox.p2.ql/about.html new file mode 100644 index 000000000..460233046 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/about.html @@ -0,0 +1,28 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>June 2, 2006</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. +For purposes of the EPL, "Program" will mean the Content.</p> + +<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p> + +</body> +</html>
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.ql/build.properties b/bundles/org.eclipse.equinox.p2.ql/build.properties new file mode 100644 index 000000000..230777f9a --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/build.properties @@ -0,0 +1,15 @@ + +# <copyright> +# </copyright> +# +# $Id$ + +bin.includes = .,\ + META-INF/,\ + plugin.properties,\ + about.html +jars.compile.order = . +source.. = src/ +output.. = bin/ +src.includes = about.html,\ + model/ diff --git a/bundles/org.eclipse.equinox.p2.ql/model/p2ql.bnf b/bundles/org.eclipse.equinox.p2.ql/model/p2ql.bnf new file mode 100644 index 000000000..476f54187 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/model/p2ql.bnf @@ -0,0 +1,67 @@ +condition + : orExpression ( '?' orExpression ':' orExpression )? + ; + +orExpression : andExpression ( '||' andExpression )* ; + +andExpression : binaryExpression ( '&&' binaryExpression )* ; + +binaryExpression : notExpression ( op notExpression )?; + +op : '=' | '!=' | '>' | '>=' | '<' | '<=' | '~=' ; + +notExpression + : '!' notExpression + | collectionExpression + ; + +collectionExpression + : memberExpression ( '.' collectionFunction )* + ; + +memberExpression : constructor ( ( '.' ID ) | ( '[' memberExpression ']' ) )* ; + +constructor + : ( filter | version | range | class ) '(' unaryExpression ')' + | set '(' ( collectionExpression ( ',' collectionExpression )* )? ')' + | unaryExpression + ; + +collectionFunction + : ( select | reject | exists | all | traverse ) '(' lambdaDefinition ')' + | limit '(' memberExpression ')' + | unique '(' memberExpression? ')' + | latest '(' lambdaDefinition? ')' + ; + +lambdaDefinition + : initializer ( ',' initializer )* ( ',' '{' lambda '}' )? + | '{' lambda '}' + | lambda + ; + +initializer + : '_' + | condition + ; + +lambda + : ( ID ( ',' ID )* )? '|' condition + ; + +unaryExpression + : '(' condition ')' + | '[' condition ( ',' condition )* ']' // #array construct + | '/' regexpPattern '/' + | STRING + | INT + | parameter + | 'null' + | 'true' + | 'false' + | ID + ; + +parameter + : '$' INT | ID + ; diff --git a/bundles/org.eclipse.equinox.p2.ql/plugin.properties b/bundles/org.eclipse.equinox.p2.ql/plugin.properties new file mode 100644 index 000000000..3223d0ec0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/plugin.properties @@ -0,0 +1,8 @@ + +# <copyright> +# </copyright> +# +# $Id$ + +pluginName = P2ql Model +providerName = www.example.org diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/All.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/All.java new file mode 100644 index 000000000..05c8a7ee3 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/All.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; + +/** + * A collection filter that yields true if the <code>filter</code> yields true for + * all of the elements of the <code>collection</code> + */ +public final class All extends CollectionFilter { + static final String OPERATOR = "all"; //$NON-NLS-1$ + + public All(Expression collection, LambdaExpression lambda) { + super(collection, lambda); + } + + Object evaluate(ExpressionContext context, VariableScope scope, Iterator itor) { + while (itor.hasNext()) { + scope.setEach(variable, itor.next()); + if (lambda.evaluate(context, scope) != Boolean.TRUE) + return Boolean.FALSE; + } + return Boolean.TRUE; + } + + String getOperator() { + return OPERATOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/And.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/And.java new file mode 100644 index 000000000..1c269c59c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/And.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.*; + +/** + * n-ary AND operator. This operator evaluates its first operand and then checks + * the class of the result. If the class is {@link Boolean} then it is assumed + * that all other operands also evaluates to a boolean and the full evaluation is + * <code>true</code> if all its operands evaluate to <code>true</code>. If the first + * result was not of class {@link Boolean}, then it is assumed that it can be accessed + * as an {@link Iterator} and that all other operands also evaluates to something that + * can be accessed as an {@link Iterator}. The AND operator will then function as a + * INTERSECT operator and the result is the set of elements that were found in all operands. + */ +public final class And extends NAry { + static final String OPERATOR = "&&"; //$NON-NLS-1$ + + public And(Expression[] operands) { + super(assertLength(operands, 2, OPERATOR)); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + Object firstValue = operands[0].evaluate(context, scope); + + // Determine operation mode + if (firstValue instanceof Boolean) { + // The first value was boolean. Assume that the rest are too + if (!((Boolean) firstValue).booleanValue()) + return Boolean.FALSE; + + for (int idx = 1; idx < operands.length; ++idx) { + if (operands[idx].evaluate(context, scope) != Boolean.TRUE) + return Boolean.FALSE; + } + return Boolean.TRUE; + } + + // Not a boolean. Assume that we can use an iterator on all values + Set resultSet = asSet(firstValue, false); // Safe since it will not be modified + for (int idx = 1; idx < operands.length && !resultSet.isEmpty(); ++idx) { + Iterator itor = operands[idx].evaluateAsIterator(context, scope); + Set retained = new HashSet(); + while (itor.hasNext()) { + Object value = itor.next(); + if (resultSet.contains(value)) + retained.add(value); + } + resultSet = retained; + } + return resultSet; + } + + String getOperator() { + return OPERATOR; + } + + int getPriority() { + return ExpressionParser.PRIORITY_AND; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Array.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Array.java new file mode 100644 index 000000000..ffada9bf4 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Array.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * An array of expressions + */ +public final class Array extends NAry { + static final String OPERATOR = "[]"; //$NON-NLS-1$ + + static void elementsToString(StringBuffer bld, Expression[] elements) { + int top = elements.length; + if (top > 0) { + elements[0].toString(bld); + for (int idx = 1; idx < top; ++idx) { + bld.append(", "); //$NON-NLS-1$ + appendOperand(bld, elements[idx], ExpressionParser.PRIORITY_COMMA); + } + } + } + + public Array(Expression[] operands) { + super(assertLength(operands, 0, OPERATOR)); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + return new ArrayIterator(context, scope, operands); + } + + public void toString(StringBuffer bld) { + bld.append('['); + elementsToString(bld, operands); + bld.append(']'); + } + + String getOperator() { + return OPERATOR; + } + + int getPriority() { + return ExpressionParser.PRIORITY_CONSTRUCTOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ArrayIterator.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ArrayIterator.java new file mode 100644 index 000000000..dc136ce65 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ArrayIterator.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * A MatchIteratorFilter controlled by an expression + */ +public class ArrayIterator implements Iterator { + private final Expression[] expressions; + + private final ExpressionContext context; + + private final VariableScope scope; + + private int pos = -1; + + public ArrayIterator(ExpressionContext context, VariableScope scope, Expression[] expressions) { + this.expressions = expressions; + this.context = context; + this.scope = scope; + } + + public boolean hasNext() { + return pos + 1 < expressions.length; + } + + public Object next() { + if (++pos >= expressions.length) { + --pos; + throw new NoSuchElementException(); + } + return expressions[pos].evaluate(context, scope); + } + + public void remove() { + throw new UnsupportedOperationException(); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/At.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/At.java new file mode 100644 index 000000000..b070a179b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/At.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit; + +/** + * This class represents indexed or keyed access to an indexed collection + * or a map. + */ +public final class At extends Binary { + public static final String OPERATOR = "[]"; //$NON-NLS-1$ + + public At(Expression lhs, Expression rhs) { + super(lhs, rhs); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + Object lval; + if (lhs instanceof Member) { + Member lm = (Member) lhs; + Object instance = lm.operand.evaluate(context, scope); + if (instance instanceof IInstallableUnit && "properties".equals(lm.name)) //$NON-NLS-1$ + // Avoid full copy of the properties map just to get one member + return ((IInstallableUnit) instance).getProperty((String) rhs.evaluate(context, scope)); + lval = lm.invoke(instance); + } else + lval = lhs.evaluate(context, scope); + + Object rval = rhs.evaluate(context, scope); + if (lval == null) + throw new IllegalArgumentException("Unable to use [] on null"); //$NON-NLS-1$ + + if (lval instanceof Map) + return ((Map) lval).get(rval); + + if (rval instanceof Number) { + if (lval instanceof List) + return ((List) lval).get(((Number) rval).intValue()); + if (lval != null && lval.getClass().isArray()) + return ((Object[]) lval)[((Number) rval).intValue()]; + } + + if (lval instanceof Dictionary) + return ((Dictionary) lval).get(rval); + + throw new IllegalArgumentException("Unable to use [] on a " + lval.getClass().getName()); //$NON-NLS-1$ + } + + public void toString(StringBuffer bld) { + appendOperand(bld, lhs, getPriority()); + bld.append('['); + appendOperand(bld, rhs, ExpressionParser.PRIORITY_COMMA); + bld.append(']'); + } + + String getOperator() { + return OPERATOR; + } + + int getPriority() { + return ExpressionParser.PRIORITY_MEMBER; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Binary.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Binary.java new file mode 100644 index 000000000..5927a08cc --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Binary.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * The abstract base class for all binary operations + */ +abstract class Binary extends Expression { + final Expression lhs; + + final Expression rhs; + + Binary(Expression lhs, Expression rhs) { + this.lhs = lhs; + this.rhs = rhs; + } + + public boolean accept(Visitor visitor) { + return super.accept(visitor) && lhs.accept(visitor) && rhs.accept(visitor); + } + + public void toString(StringBuffer bld) { + appendOperand(bld, lhs, getPriority()); + bld.append(' '); + bld.append(getOperator()); + bld.append(' '); + appendOperand(bld, rhs, getPriority()); + } + + int countReferenceToEverything() { + return lhs.countReferenceToEverything() + rhs.countReferenceToEverything(); + } + + abstract String getOperator(); + + int getPriority() { + return ExpressionParser.PRIORITY_BINARY; // Default priority + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ClassConstructor.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ClassConstructor.java new file mode 100644 index 000000000..4f00acfa7 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ClassConstructor.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +public class ClassConstructor extends Constructor { + + static final String KEYWORD = "class"; //$NON-NLS-1$ + + public ClassConstructor(Expression[] operands) { + super(operands); + } + + Object createInstance(String arg) { + try { + return Class.forName(arg); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException(e.getMessage()); + } + } + + String getOperator() { + return KEYWORD; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Collect.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Collect.java new file mode 100644 index 000000000..87a2d4801 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Collect.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; + +/** + * An expression that yields a new collection consisting of all elements of the + * <code>collection</code> for which the <code>filter</code> yields <code>true</code>. + */ +public final class Collect extends CollectionFilter { + public static final String OPERATOR = "collect"; //$NON-NLS-1$ + + public Collect(Expression collection, LambdaExpression lambda) { + super(collection, lambda); + } + + Object evaluate(ExpressionContext context, VariableScope scope, Iterator itor) { + return new CollectIterator(context, scope, variable, itor, lambda); + } + + String getOperator() { + return OPERATOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/CollectIterator.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/CollectIterator.java new file mode 100644 index 000000000..787c6236e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/CollectIterator.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; + +/** + * A MatchIteratorFilter controlled by an expression + */ +public class CollectIterator implements Iterator { + private final Expression expression; + + private final ExpressionContext context; + + private final VariableScope scope; + + private final EachVariable variable; + + private final Iterator innerIterator; + + public CollectIterator(ExpressionContext context, VariableScope scope, EachVariable variable, Iterator iterator, Expression expression) { + this.expression = expression; + this.context = context; + this.scope = scope; + this.variable = variable; + this.innerIterator = iterator; + } + + public boolean hasNext() { + return innerIterator.hasNext(); + } + + public Object next() { + variable.setValue(scope, innerIterator.next()); + return expression.evaluate(context, scope); + } + + public void remove() { + throw new UnsupportedOperationException(); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/CollectionFilter.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/CollectionFilter.java new file mode 100644 index 000000000..66e530d4a --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/CollectionFilter.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; + +/** + * Some kind of operation that is performed for each element of a collection. I.e. + * <code>x.<operation>(y | <expression&rt;)</code> + */ +abstract class CollectionFilter extends Unary { + static void appendProlog(StringBuffer bld, Expression lhs, String operator) { + if (lhs != Variable.EVERYTHING && lhs != Variable.ITEM) { + appendOperand(bld, lhs, ExpressionParser.PRIORITY_COLLECTION); + bld.append('.'); + } + bld.append(operator); + bld.append('('); + } + + final LambdaExpression lambda; + final EachVariable variable; + + CollectionFilter(Expression collection, LambdaExpression lambda) { + super(collection); + this.lambda = lambda; + this.variable = lambda.getItemVariable(); + } + + public boolean accept(Visitor visitor) { + return super.accept(visitor) && lambda.accept(visitor); + } + + public final Object evaluate(ExpressionContext context, VariableScope scope) { + Iterator lval = operand.evaluateAsIterator(context, scope); + scope = lambda.prolog(context, scope); + return evaluate(context, scope, lval); + } + + public void toString(StringBuffer bld) { + appendProlog(bld, operand, getOperator()); + appendOperand(bld, lambda, ExpressionParser.PRIORITY_LAMBDA); + bld.append(')'); + } + + int countReferenceToEverything() { + return super.countReferenceToEverything() + lambda.countReferenceToEverything(); + } + + abstract Object evaluate(final ExpressionContext context, final VariableScope scope, Iterator iterator); + + int getPriority() { + return ExpressionParser.PRIORITY_COLLECTION; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Compare.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Compare.java new file mode 100644 index 000000000..75962fdf5 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Compare.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import org.eclipse.equinox.internal.provisional.p2.metadata.Version; + +/** + * Comparisons for magnitude. + */ +public final class Compare extends Binary { + static final String LT_OPERATOR = "<"; //$NON-NLS-1$ + static final String LT_EQUAL_OPERATOR = "<="; //$NON-NLS-1$ + static final String GT_OPERATOR = ">"; //$NON-NLS-1$ + static final String GT_EQUAL_OPERATOR = ">="; //$NON-NLS-1$ + + private final boolean compareLess; + private final boolean equalOK; + + public Compare(Expression lhs, Expression rhs, boolean compareLess, boolean equalOK) { + super(lhs, rhs); + this.compareLess = compareLess; + this.equalOK = equalOK; + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + Object lval = lhs.evaluate(context, scope); + Object rval = rhs.evaluate(context, scope); + if (lval == null || rval == null) + throw new IllegalArgumentException("Cannot compare null to anything"); //$NON-NLS-1$ + + try { + + if (lval.getClass() != rval.getClass()) { + if (lval instanceof Version && rval instanceof String) + rval = Version.create((String) rval); + else if (rval instanceof Version && lval instanceof String) + lval = Version.create((String) lval); + else if (lval instanceof String) + rval = rval.toString(); + else if (rval instanceof String) + lval = lval.toString(); + } + + if (lval instanceof Comparable) { + int cmpResult = ((Comparable) lval).compareTo(rval); + return Boolean.valueOf(cmpResult == 0 ? equalOK : (cmpResult < 0 ? compareLess : !compareLess)); + } + } catch (Exception e) { + // + } + throw new IllegalArgumentException("Cannot compare a " + lval.getClass().getName() + " to a " + rval.getClass().getName()); //$NON-NLS-1$//$NON-NLS-2$ + } + + String getOperator() { + return compareLess ? (equalOK ? LT_EQUAL_OPERATOR : LT_OPERATOR) : (equalOK ? GT_EQUAL_OPERATOR : GT_OPERATOR); + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Condition.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Condition.java new file mode 100644 index 000000000..0302e631f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Condition.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * Comparisons for magnitude. + */ +public final class Condition extends Binary { + static final String IF_OPERATOR = "?"; //$NON-NLS-1$ + static final String ELSE_OPERATOR = ":"; //$NON-NLS-1$ + + final Expression ifFalse; + + public Condition(Expression test, Expression ifTrue, Expression ifFalse) { + super(test, ifTrue); + this.ifFalse = ifFalse; + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + return lhs.evaluate(context, scope) == Boolean.TRUE ? rhs.evaluate(context, scope) : ifFalse.evaluate(context, scope); + } + + public void toString(StringBuffer bld) { + super.toString(bld); + bld.append(' '); + bld.append(ELSE_OPERATOR); + bld.append(' '); + appendOperand(bld, ifFalse, getPriority()); + } + + String getOperator() { + return IF_OPERATOR; + } + + int getPriority() { + return ExpressionParser.PRIORITY_CONDITION; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Constant.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Constant.java new file mode 100644 index 000000000..d358b4084 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Constant.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * An expression that represents a constant value. + */ +public final class Constant extends Expression { + private final Object value; + + public static final Constant NULL_CONSTANT = new Constant(null); + + public static final Constant TRUE_CONSTANT = new Constant(Boolean.TRUE); + + public static final Constant FALSE_CONSTANT = new Constant(Boolean.FALSE); + + static final String NULL_KEYWORD = "null"; //$NON-NLS-1$ + + static final String FALSE_KEYWORD = "false"; //$NON-NLS-1$ + + static final String TRUE_KEYWORD = "true"; //$NON-NLS-1$ + + public Constant(Object value) { + this.value = value; + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + return value; + } + + public void toString(StringBuffer bld) { + if (value == null) + bld.append("null"); //$NON-NLS-1$ + else if (value instanceof String) { + String str = (String) value; + char sep = str.indexOf('\'') >= 0 ? '"' : '\''; + bld.append(sep); + bld.append(str); + bld.append(sep); + } else if (value instanceof SimplePattern) { + appendEscaped(bld, '/', value.toString()); + } else + bld.append(value); + } + + int getPriority() { + return ExpressionParser.PRIORITY_LITERAL; + } + + private void appendEscaped(StringBuffer bld, char delimiter, String str) { + bld.append(delimiter); + int top = str.length(); + for (int idx = 0; idx < top; ++idx) { + char c = str.charAt(idx); + if (c == delimiter) + bld.append('\\'); + bld.append(c); + } + bld.append(delimiter); + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Constructor.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Constructor.java new file mode 100644 index 000000000..d3b8637ad --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Constructor.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * An expression that represents a constructor such as filter(<expr>) or version(<expr>) + */ +public abstract class Constructor extends NAry { + + private Object instance; + + Constructor(Expression[] operands) { + super(operands); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + if (instance != null) + return instance; + + Expression operand = operands[0]; + Object arg = operand.evaluate(context, scope); + if (arg instanceof String) { + Object result = createInstance((String) arg); + if (operand instanceof Constant || operand instanceof Parameter) + // operand won't change over time so we can cache this instance. + instance = result; + return result; + } + String what = arg == null ? "null" : ("a " + arg.getClass().getName()); //$NON-NLS-1$ //$NON-NLS-2$ + throw new IllegalArgumentException("Cannot create a " + getOperator() + " from " + what); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public void toString(StringBuffer bld) { + bld.append(getOperator()); + bld.append('('); + Array.elementsToString(bld, operands); + bld.append(')'); + } + + Object createInstance(String arg) { + throw new UnsupportedOperationException(); + } + + int getPriority() { + return ExpressionParser.PRIORITY_CONSTRUCTOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ContextExpression.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ContextExpression.java new file mode 100644 index 000000000..3f377664b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ContextExpression.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + + +/** + * The context expression is the top expression in context queries. It introduces the + * variable 'everything' and initialized it with the iterator that represents all + * available items. + */ +public final class ContextExpression extends Binary { + + public ContextExpression(Variable contextVariable, Expression expression) { + super(contextVariable, expression); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + ((Variable) lhs).setValue(scope, context); + return rhs.evaluate(context, scope); + } + + public void toString(StringBuffer bld) { + rhs.toString(bld); + } + + int countReferenceToEverything() { + return rhs.countReferenceToEverything(); + } + + String getOperator() { + throw new UnsupportedOperationException(); + } + + int getPriority() { + return rhs.getPriority(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/EachVariable.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/EachVariable.java new file mode 100644 index 000000000..b3d8f9d6e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/EachVariable.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * An expression representing a variable stack in the current thread. + */ +final class EachVariable extends Variable { + static final String KEYWORD_EACH = "_"; //$NON-NLS-1$ + + EachVariable(String name) { + super(name); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + return scope.getEach(this); + } + + int countReferenceToEverything() { + return 0; + } + + void setValue(VariableScope scope, Object value) { + scope.setEach(this, value); + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Equals.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Equals.java new file mode 100644 index 000000000..32ce25b55 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Equals.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * An expression that performs the == and != comparisons + */ +public final class Equals extends Binary { + static final String EQUALS_OPERATOR = "=="; //$NON-NLS-1$ + static final String NOT_EQUALS_OPERATOR = "!="; //$NON-NLS-1$ + + private final boolean negate; + + public Equals(Expression lhs, Expression rhs) { + this(lhs, rhs, false); + } + + public Equals(Expression lhs, Expression rhs, boolean negate) { + super(lhs, rhs); + this.negate = negate; + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + Object lval = lhs.evaluate(context, scope); + Object rval = rhs.evaluate(context, scope); + boolean result; + if (lval == null || rval == null) + result = lval == rval; + else { + if (lval.getClass() != rval.getClass()) { + if (lval instanceof String) + rval = rval.toString(); + else if (rval instanceof String) + lval = lval.toString(); + } + result = lval.equals(rval); + } + if (negate) + result = !result; + return Boolean.valueOf(result); + } + + String getOperator() { + return negate ? NOT_EQUALS_OPERATOR : EQUALS_OPERATOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Exists.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Exists.java new file mode 100644 index 000000000..d1a110d03 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Exists.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; + +/** + * A collection filter that yields true if the <code>filter</code> yields true for + * any of the elements of the <code>collection</code> + */ +public final class Exists extends CollectionFilter { + public static final String OPERATOR = "exists"; //$NON-NLS-1$ + + public Exists(Expression collection, LambdaExpression lambda) { + super(collection, lambda); + } + + Object evaluate(ExpressionContext context, VariableScope scope, Iterator itor) { + while (itor.hasNext()) { + scope.setEach(variable, itor.next()); + if (lambda.evaluate(context, scope) == Boolean.TRUE) + return Boolean.TRUE; + } + return Boolean.FALSE; + } + + String getOperator() { + return OPERATOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Expression.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Expression.java new file mode 100644 index 000000000..746a680db --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Expression.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.query.Collector; + +/** + * The base class of the expression tree. + */ +public abstract class Expression { + + public interface Visitor { + /** + * The method that will be called for each expression that is + * visited. + * @param expression The expression that the visitor visits. + * @return <code>true</code> to continue visiting other expressions or + * <code>false</code> to break out. + */ + boolean accept(Expression expression); + } + + public static final Expression[] emptyArray = new Expression[0]; + + static Set asSet(Object val, boolean forcePrivateCopy) { + if (val == null) + throw new IllegalArgumentException("Cannot convert null into an set"); //$NON-NLS-1$ + + if (val instanceof IRepeatableIterator) { + Object provider = ((IRepeatableIterator) val).getIteratorProvider(); + if (!forcePrivateCopy) { + if (provider instanceof Set) + return (Set) provider; + if (provider instanceof Collector) + return (Set) ((Collector) provider).toCollection(); + } + + if (provider instanceof Collection) + val = provider; + } else { + if (!forcePrivateCopy) { + if (val instanceof Set) + return (Set) val; + if (val instanceof Collector) + return (Set) ((Collector) val).toCollection(); + } + } + + HashSet result; + if (val instanceof Collection) + result = new HashSet((Collection) val); + else { + result = new HashSet(); + Iterator iterator = RepeatableIterator.create(val); + while (iterator.hasNext()) + result.add(iterator.next()); + } + return result; + } + + /** + * Let the visitor visit this instance and all expressions that this + * instance contains. + * @param visitor The visiting visitor. + * @return <code>true</code> if the visitor should continue visiting, <code>false</code> otherwise. + */ + public boolean accept(Visitor visitor) { + return visitor.accept(this); + } + + /** + * Evaluate this expression in the given context. + * @param scope TODO + * @return The result of the evaluation. + */ + public abstract Object evaluate(ExpressionContext context, VariableScope scope); + + public Iterator evaluateAsIterator(ExpressionContext context, VariableScope scope) { + Object value = evaluate(context, scope); + if (!(value instanceof Iterator)) + value = RepeatableIterator.create(value); + return (Iterator) value; + } + + /** + * Checks if the expression will make repeated requests for the 'everything' iterator. + * @return <code>true</code> if repeated requests will be made, <code>false</code> if not. + */ + public boolean needsRepeatedIterations() { + return countReferenceToEverything() > 1; + } + + public String toString() { + StringBuffer bld = new StringBuffer(); + toString(bld); + return bld.toString(); + } + + public abstract void toString(StringBuffer bld); + + static void appendOperand(StringBuffer bld, Expression operand, int priority) { + if (priority < operand.getPriority()) { + bld.append('('); + operand.toString(bld); + bld.append(')'); + } else + operand.toString(bld); + } + + int countReferenceToEverything() { + return 0; + } + + abstract int getPriority(); +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ExpressionContext.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ExpressionContext.java new file mode 100644 index 000000000..150689d1e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ExpressionContext.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.*; + +/** + * The immutable context used when evaluating an expression. + */ +public final class ExpressionContext implements IRepeatableIterator { + private static final Object[] noParameters = new Object[0]; + + private final Iterator iterator; + + private final Class instanceClass; + + private final Object[] parameters; + + private boolean atStart = true; + + public ExpressionContext(Class instanceClass, Object[] parameters, Collection collection) { + this.instanceClass = instanceClass; + this.parameters = parameters == null ? noParameters : parameters; + this.iterator = RepeatableIterator.create(collection == null ? Collections.EMPTY_LIST : collection); + } + + public ExpressionContext(Class instanceClass, Object[] parameters, final Iterator iterator, boolean needsRepeat) { + this.instanceClass = instanceClass; + this.parameters = parameters; + this.iterator = needsRepeat ? RepeatableIterator.create(iterator) : iterator; + } + + public Class getInstanceClass() { + return instanceClass; + } + + public Object getParameter(int position) { + return parameters[position]; + } + + public Object getParameter(String key) { + return parameters.length == 1 && parameters[0] instanceof Map ? ((Map) parameters[0]).get(key) : null; + } + + public IRepeatableIterator getCopy() { + if (iterator instanceof IRepeatableIterator) + return ((IRepeatableIterator) iterator).getCopy(); + if (atStart) + return this; + throw new UnsupportedOperationException(); + } + + public boolean hasNext() { + return iterator.hasNext(); + } + + public Object next() { + atStart = false; + return iterator.next(); + } + + public void remove() { + iterator.remove(); + } + + public Object getIteratorProvider() { + if (iterator instanceof IRepeatableIterator) + return ((IRepeatableIterator) iterator).getIteratorProvider(); + return this; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ExpressionFilter.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ExpressionFilter.java new file mode 100644 index 000000000..4935e7bd0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ExpressionFilter.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; + +/** + * A MatchIteratorFilter controlled by an expression + */ +public class ExpressionFilter extends MatchIteratorFilter { + private final ItemExpression expression; + + private final ExpressionContext context; + + private final VariableScope scope; + + public ExpressionFilter(ExpressionContext context, VariableScope scope, Iterator iterator, ItemExpression expression) { + super(context.getInstanceClass(), iterator); + this.expression = expression; + this.context = context; + this.scope = scope; + } + + protected boolean isMatch(Object val) { + return expression.isMatch(context, scope, val); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ExpressionParser.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ExpressionParser.java new file mode 100644 index 000000000..00b1dc2f7 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ExpressionParser.java @@ -0,0 +1,867 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.lang.reflect.InvocationTargetException; +import java.util.*; + +public class ExpressionParser extends Stack { + private static final long serialVersionUID = 882034383978853143L; + + static final int PRIORITY_PARAMETER = 1; + static final int PRIORITY_LITERAL = 1; + static final int PRIORITY_VARIABLE = 1; + static final int PRIORITY_CONSTRUCTOR = 2; + static final int PRIORITY_MEMBER = 3; + static final int PRIORITY_COLLECTION = 4; + static final int PRIORITY_NOT = 5; + static final int PRIORITY_BINARY = 6; + static final int PRIORITY_AND = 7; + static final int PRIORITY_OR = 8; + static final int PRIORITY_CONDITION = 9; + static final int PRIORITY_LAMBDA = 10; + static final int PRIORITY_COMMA = 11; + + private static final int TOKEN_OR = 1; + private static final int TOKEN_AND = 2; + + private static final int TOKEN_EQUAL = 10; + private static final int TOKEN_NOT_EQUAL = 11; + private static final int TOKEN_LESS = 12; + private static final int TOKEN_LESS_EQUAL = 13; + private static final int TOKEN_GREATER = 14; + private static final int TOKEN_GREATER_EQUAL = 15; + private static final int TOKEN_MATCHES = 16; + + private static final int TOKEN_NOT = 20; + private static final int TOKEN_DOT = 21; + private static final int TOKEN_COMMA = 22; + private static final int TOKEN_PIPE = 23; + private static final int TOKEN_DOLLAR = 24; + private static final int TOKEN_IF = 25; + private static final int TOKEN_ELSE = 26; + + private static final int TOKEN_LP = 30; + private static final int TOKEN_RP = 31; + private static final int TOKEN_LB = 32; + private static final int TOKEN_RB = 33; + private static final int TOKEN_LC = 34; + private static final int TOKEN_RC = 35; + + private static final int TOKEN_IDENTIFIER = 40; + private static final int TOKEN_LITERAL = 41; + private static final int TOKEN_ANY = 42; + + private static final int TOKEN_NULL = 50; + private static final int TOKEN_TRUE = 51; + private static final int TOKEN_FALSE = 52; + + private static final int TOKEN_LATEST = 60; + private static final int TOKEN_LIMIT = 61; + private static final int TOKEN_FIRST = 62; + private static final int TOKEN_FLATTEN = 63; + private static final int TOKEN_SELECT = 64; + private static final int TOKEN_REJECT = 65; + private static final int TOKEN_COLLECT = 66; + private static final int TOKEN_EXISTS = 67; + private static final int TOKEN_ALL = 68; + private static final int TOKEN_TRAVERSE = 69; + private static final int TOKEN_UNIQUE = 70; + + private static final int TOKEN_END = 0; + private static final int TOKEN_ERROR = -1; + + private static final Variable[] emptyVariableArray = new Variable[0]; + + private static final Map constructors; + + static { + Class[] args = new Class[] {Expression[].class}; + constructors = new HashMap(); + try { + constructors.put(FilterConstructor.KEYWORD, FilterConstructor.class.getConstructor(args)); + constructors.put(VersionConstructor.KEYWORD, VersionConstructor.class.getConstructor(args)); + constructors.put(RangeConstructor.KEYWORD, RangeConstructor.class.getConstructor(args)); + constructors.put(SetConstructor.KEYWORD, SetConstructor.class.getConstructor(args)); + constructors.put(ClassConstructor.KEYWORD, ClassConstructor.class.getConstructor(args)); + constructors.put(WrappedIQuery.KEYWORD, WrappedIQuery.class.getConstructor(args)); + constructors.put(LocalizedKeys.KEYWORD, LocalizedKeys.class.getConstructor(args)); + constructors.put(LocalizedMap.KEYWORD, LocalizedMap.class.getConstructor(args)); + constructors.put(LocalizedProperty.KEYWORD, LocalizedProperty.class.getConstructor(args)); + } catch (Exception e) { + throw new ExceptionInInitializerError(e); + } + } + + private String expression; + private int tokenPos; + private int currentToken; + private int lastTokenPos; + private Object tokenValue; + private String rootVariable; + + public synchronized ItemExpression parsePredicate(String exprString) { + expression = exprString; + tokenPos = 0; + currentToken = 0; + tokenValue = null; + rootVariable = Variable.KEYWORD_ITEM; + push(Variable.ITEM); + try { + nextToken(); + Expression expr = currentToken == TOKEN_END ? Constant.TRUE_CONSTANT : parseCondition(); + assertToken(TOKEN_END); + return new ItemExpression(Variable.ITEM, expr); + } finally { + popVariable(); // pop item + } + } + + public synchronized ContextExpression parseQuery(String exprString) { + expression = exprString; + tokenPos = 0; + currentToken = 0; + tokenValue = null; + rootVariable = Variable.KEYWORD_EVERYTHING; + push(Variable.EVERYTHING); + try { + nextToken(); + Expression expr = parseCondition(); + assertToken(TOKEN_END); + return new ContextExpression(Variable.EVERYTHING, expr); + + } finally { + popVariable(); // pop context + } + } + + private Expression parseCondition() { + Expression expr = parseOr(); + if (currentToken == TOKEN_IF) { + nextToken(); + Expression ifTrue = parseOr(); + assertToken(TOKEN_ELSE); + nextToken(); + expr = new Condition(expr, ifTrue, parseOr()); + } + return expr; + } + + private Expression parseOr() { + Expression expr = parseAnd(); + if (currentToken != TOKEN_OR) + return expr; + + ArrayList exprs = new ArrayList(); + exprs.add(expr); + do { + nextToken(); + exprs.add(parseAnd()); + } while (currentToken == TOKEN_OR); + return new Or((Expression[]) exprs.toArray(new Expression[exprs.size()])); + } + + private Expression parseAnd() { + Expression expr = parseBinary(); + if (currentToken != TOKEN_AND) + return expr; + + ArrayList exprs = new ArrayList(); + exprs.add(expr); + do { + nextToken(); + exprs.add(parseBinary()); + } while (currentToken == TOKEN_AND); + return new And((Expression[]) exprs.toArray(new Expression[exprs.size()])); + } + + private Expression parseBinary() { + Expression expr = parseNot(); + switch (currentToken) { + case TOKEN_OR : + case TOKEN_AND : + case TOKEN_RP : + case TOKEN_RB : + case TOKEN_RC : + case TOKEN_COMMA : + case TOKEN_IF : + case TOKEN_ELSE : + case TOKEN_END : + break; + case TOKEN_EQUAL : + case TOKEN_NOT_EQUAL : + case TOKEN_GREATER : + case TOKEN_GREATER_EQUAL : + case TOKEN_LESS : + case TOKEN_LESS_EQUAL : + case TOKEN_MATCHES : + int realToken = currentToken; + nextToken(); + Expression rhs = parseNot(); + switch (realToken) { + case TOKEN_EQUAL : + expr = new Equals(expr, rhs, false); + break; + case TOKEN_NOT_EQUAL : + expr = new Equals(expr, rhs, true); + break; + case TOKEN_GREATER : + expr = new Compare(expr, rhs, false, false); + break; + case TOKEN_GREATER_EQUAL : + expr = new Compare(expr, rhs, false, true); + break; + case TOKEN_LESS : + expr = new Compare(expr, rhs, true, false); + break; + case TOKEN_LESS_EQUAL : + expr = new Compare(expr, rhs, true, true); + break; + default : + expr = new Matches(expr, rhs); + } + break; + default : + throw syntaxError(); + } + return expr; + } + + private Expression parseNot() { + if (currentToken == TOKEN_NOT) { + nextToken(); + Expression expr = parseNot(); + return (expr instanceof Not) ? ((Not) expr).operand : new Not(expr); + } + return parseCollectionExpression(); + } + + private Expression parseCollectionExpression() { + Expression expr; + switch (currentToken) { + case TOKEN_SELECT : + case TOKEN_REJECT : + case TOKEN_COLLECT : + case TOKEN_EXISTS : + case TOKEN_FIRST : + case TOKEN_FLATTEN : + case TOKEN_ALL : + case TOKEN_TRAVERSE : + case TOKEN_LATEST : + case TOKEN_LIMIT : + case TOKEN_UNIQUE : + expr = getVariableOrRootMember(rootVariable); + break; + default : + expr = parseMember(); + if (currentToken != TOKEN_DOT) + return expr; + nextToken(); + } + + for (;;) { + int filterToken = currentToken; + nextToken(); + assertToken(TOKEN_LP); + nextToken(); + switch (filterToken) { + case TOKEN_SELECT : + expr = new Select(expr, parseLambdaDefinition()); + break; + case TOKEN_REJECT : + expr = new Reject(expr, parseLambdaDefinition()); + break; + case TOKEN_COLLECT : + expr = new Collect(expr, parseLambdaDefinition()); + break; + case TOKEN_EXISTS : + expr = new Exists(expr, parseLambdaDefinition()); + break; + case TOKEN_FIRST : + expr = new First(expr, parseLambdaDefinition()); + break; + case TOKEN_ALL : + expr = new All(expr, parseLambdaDefinition()); + break; + case TOKEN_TRAVERSE : + expr = new Traverse(expr, parseLambdaDefinition()); + break; + case TOKEN_LATEST : + if (currentToken == TOKEN_RP) { + expr = new Latest(expr); + assertToken(TOKEN_RP); + nextToken(); + } else + expr = new Latest(new Select(expr, parseLambdaDefinition())); + break; + case TOKEN_FLATTEN : + if (currentToken == TOKEN_RP) { + expr = new Flatten(expr); + assertToken(TOKEN_RP); + nextToken(); + } else + expr = new Flatten(new Select(expr, parseLambdaDefinition())); + break; + case TOKEN_LIMIT : + expr = new Limit(expr, parseMember()); + assertToken(TOKEN_RP); + nextToken(); + break; + case TOKEN_UNIQUE : + if (currentToken == TOKEN_RP) + expr = new Unique(expr, Constant.NULL_CONSTANT); + else { + expr = new Unique(expr, parseMember()); + assertToken(TOKEN_RP); + nextToken(); + } + break; + default : + throw syntaxError(); + } + if (currentToken != TOKEN_DOT) + break; + nextToken(); + } + return expr; + } + + private Expression parseMember() { + Expression expr = parseConstructor(); + while (currentToken == TOKEN_DOT || currentToken == TOKEN_LB) { + int savePos = tokenPos; + int saveToken = currentToken; + Object saveTokenValue = tokenValue; + nextToken(); + if (saveToken == TOKEN_DOT) { + switch (currentToken) { + case TOKEN_SELECT : + case TOKEN_REJECT : + case TOKEN_COLLECT : + case TOKEN_EXISTS : + case TOKEN_FIRST : + case TOKEN_FLATTEN : + case TOKEN_ALL : + case TOKEN_TRAVERSE : + case TOKEN_LATEST : + case TOKEN_LIMIT : + case TOKEN_UNIQUE : + tokenPos = savePos; + currentToken = saveToken; + tokenValue = saveTokenValue; + return expr; + + case TOKEN_IDENTIFIER : + expr = new Member(expr, (String) tokenValue); + nextToken(); + break; + + default : + throw syntaxError(); + } + } else { + Expression atExpr = parseMember(); + assertToken(TOKEN_RB); + nextToken(); + expr = new At(expr, atExpr); + } + } + return expr; + } + + private LambdaExpression parseLambdaDefinition() { + boolean endingRC = false; + Expression[] initializers = Expression.emptyArray; + Variable[] variables; + if (currentToken == TOKEN_LC) { + // Lambda starts without currying. + endingRC = true; + nextToken(); + variables = parseVariables(0); + if (variables == null) + // empty means no pipe at the end. + throw syntaxError(); + } else { + variables = parseVariables(0); + if (variables == null) { + initializers = parseArray(); + assertToken(TOKEN_LC); + nextToken(); + endingRC = true; + int anyIndex = -1; + for (int idx = 0; idx < initializers.length; ++idx) + if (initializers[idx] instanceof EachVariable) { + anyIndex = idx; + break; + } + + variables = parseVariables(anyIndex); + if (variables == null) + // empty means no pipe at the end. + throw syntaxError(); + } + + } + nextToken(); + Expression body = parseCondition(); + if (endingRC) { + assertToken(TOKEN_RC); + nextToken(); + } + + assertToken(TOKEN_RP); + nextToken(); + return new LambdaExpression(body, initializers, variables); + } + + private Variable[] parseVariables(int anyIndex) { + int savePos = tokenPos; + int saveToken = currentToken; + Object saveTokenValue = tokenValue; + List ids = null; + while (currentToken == TOKEN_IDENTIFIER) { + if (ids == null) + ids = new ArrayList(); + ids.add(tokenValue); + nextToken(); + if (currentToken == TOKEN_COMMA) { + nextToken(); + continue; + } + break; + } + + if (currentToken != TOKEN_PIPE) { + // This was not a variable list + tokenPos = savePos; + currentToken = saveToken; + tokenValue = saveTokenValue; + return null; + } + + if (ids == null) + // Empty list but otherwise OK + return emptyVariableArray; + + int top = ids.size(); + Variable[] result = new Variable[top]; + if (top == 1) { + String name = (String) ids.get(0); + Variable each = new EachVariable(name); + push(each); + result[0] = each; + } else + for (int idx = 0; idx < top; ++idx) { + String name = (String) ids.get(idx); + Variable each; + if (idx == anyIndex) + each = new EachVariable(name); + else + each = Variable.create(name); + push(each); + result[idx] = each; + } + return result; + } + + private Expression parseConstructor() { + if (currentToken == TOKEN_IDENTIFIER) { + int savePos = tokenPos; + int saveToken = currentToken; + Object saveTokenValue = tokenValue; + + java.lang.reflect.Constructor ctor = (java.lang.reflect.Constructor) constructors.get(tokenValue); + if (ctor != null) { + nextToken(); + if (currentToken == TOKEN_LP) { + // This is a constructor(<expr>) + nextToken(); + Expression[] args = currentToken == TOKEN_RP ? Expression.emptyArray : parseArray(); + assertToken(TOKEN_RP); + nextToken(); + try { + return (Expression) ctor.newInstance(new Object[] {args}); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof RuntimeException) + throw (RuntimeException) cause; + throw new RuntimeException("Internal bogus", cause); //$NON-NLS-1$ + } catch (Exception e) { + // This should never happen. + throw new RuntimeException("Internal bogus", e); //$NON-NLS-1$ + } + } + tokenPos = savePos; + currentToken = saveToken; + tokenValue = saveTokenValue; + } + } + return parseUnary(); + } + + private Expression parseUnary() { + Expression expr; + switch (currentToken) { + case TOKEN_LP : + nextToken(); + expr = parseCondition(); + assertToken(TOKEN_RP); + nextToken(); + break; + case TOKEN_LB : + nextToken(); + expr = new Array(parseArray()); + assertToken(TOKEN_RB); + nextToken(); + break; + case TOKEN_LITERAL : + expr = new Constant(tokenValue); + nextToken(); + break; + case TOKEN_DOLLAR : + expr = parseParameter(); + break; + case TOKEN_IDENTIFIER : + expr = getVariableOrRootMember((String) tokenValue); + nextToken(); + break; + case TOKEN_ANY : + expr = new EachVariable(EachVariable.KEYWORD_EACH); + nextToken(); + break; + case TOKEN_NULL : + expr = Constant.NULL_CONSTANT; + nextToken(); + break; + case TOKEN_TRUE : + expr = Constant.TRUE_CONSTANT; + nextToken(); + break; + case TOKEN_FALSE : + expr = Constant.FALSE_CONSTANT; + nextToken(); + break; + default : + throw syntaxError(); + } + return expr; + } + + private Expression parseParameter() { + if (currentToken == TOKEN_DOLLAR) { + nextToken(); + + Parameter param = null; + if (currentToken == TOKEN_LITERAL && tokenValue instanceof Integer) + param = new IndexedParameter(((Integer) tokenValue).intValue()); + else if (currentToken == TOKEN_IDENTIFIER) + param = new KeyedParameter((String) tokenValue); + + if (param != null) { + nextToken(); + return param; + } + } + throw syntaxError(); + } + + private Expression[] parseArray() { + Expression expr = parseCondition(); + if (currentToken != TOKEN_COMMA) + return new Expression[] {expr}; + + ArrayList operands = new ArrayList(); + operands.add(expr); + do { + nextToken(); + if (currentToken == TOKEN_LC) + // We don't allow lambdas in the array + break; + operands.add(parseCondition()); + } while (currentToken == TOKEN_COMMA); + return (Expression[]) operands.toArray(new Expression[operands.size()]); + } + + private void assertToken(int token) { + if (currentToken != token) + throw syntaxError(); + } + + private Expression getVariableOrRootMember(String id) { + int idx = size(); + while (--idx >= 0) { + Variable v = (Variable) get(idx); + if (id.equals(v.getName())) + return v; + } + + if (rootVariable.equals(id)) + throw syntaxError("No such variable: " + id); //$NON-NLS-1$ + + return new Member(getVariableOrRootMember(rootVariable), id); + } + + private void nextToken() { + tokenValue = null; + int top = expression.length(); + char c = 0; + while (tokenPos < top) { + c = expression.charAt(tokenPos); + if (!Character.isWhitespace(c)) + break; + ++tokenPos; + } + if (tokenPos >= top) { + lastTokenPos = top; + currentToken = TOKEN_END; + return; + } + + lastTokenPos = tokenPos; + switch (c) { + case '|' : + if (tokenPos + 1 < top && expression.charAt(tokenPos + 1) == '|') { + tokenValue = Or.OPERATOR; + currentToken = TOKEN_OR; + tokenPos += 2; + } else { + currentToken = TOKEN_PIPE; + ++tokenPos; + } + break; + + case '&' : + if (tokenPos + 1 < top && expression.charAt(tokenPos + 1) == '&') { + tokenValue = And.OPERATOR; + currentToken = TOKEN_AND; + tokenPos += 2; + } else + currentToken = TOKEN_ERROR; + break; + + case '=' : + if (tokenPos + 1 < top && expression.charAt(tokenPos + 1) == '=') { + tokenValue = Equals.EQUALS_OPERATOR; + currentToken = TOKEN_EQUAL; + tokenPos += 2; + } else + currentToken = TOKEN_ERROR; + break; + + case '!' : + if (tokenPos + 1 < top && expression.charAt(tokenPos + 1) == '=') { + tokenValue = Equals.NOT_EQUALS_OPERATOR; + currentToken = TOKEN_NOT_EQUAL; + tokenPos += 2; + } else { + currentToken = TOKEN_NOT; + ++tokenPos; + } + break; + + case '~' : + if (tokenPos + 1 < top && expression.charAt(tokenPos + 1) == '=') { + tokenValue = Matches.OPERATOR; + currentToken = TOKEN_MATCHES; + tokenPos += 2; + } else + currentToken = TOKEN_ERROR; + break; + + case '>' : + if (tokenPos + 1 < top && expression.charAt(tokenPos + 1) == '=') { + tokenValue = Compare.GT_EQUAL_OPERATOR; + currentToken = TOKEN_GREATER_EQUAL; + tokenPos += 2; + } else { + currentToken = TOKEN_GREATER; + ++tokenPos; + } + break; + + case '<' : + if (tokenPos + 1 < top && expression.charAt(tokenPos + 1) == '=') { + tokenValue = Compare.LT_EQUAL_OPERATOR; + currentToken = TOKEN_LESS_EQUAL; + tokenPos += 2; + } else { + currentToken = TOKEN_LESS; + ++tokenPos; + } + break; + + case '?' : + currentToken = TOKEN_IF; + ++tokenPos; + break; + + case ':' : + currentToken = TOKEN_ELSE; + ++tokenPos; + break; + + case '.' : + currentToken = TOKEN_DOT; + ++tokenPos; + break; + + case '$' : + currentToken = TOKEN_DOLLAR; + ++tokenPos; + break; + + case '{' : + currentToken = TOKEN_LC; + ++tokenPos; + break; + + case '}' : + currentToken = TOKEN_RC; + ++tokenPos; + break; + + case '(' : + currentToken = TOKEN_LP; + ++tokenPos; + break; + + case ')' : + currentToken = TOKEN_RP; + ++tokenPos; + break; + + case '[' : + currentToken = TOKEN_LB; + ++tokenPos; + break; + + case ']' : + currentToken = TOKEN_RB; + ++tokenPos; + break; + + case ',' : + currentToken = TOKEN_COMMA; + ++tokenPos; + break; + + case '"' : + case '\'' : { + int start = ++tokenPos; + while (tokenPos < top && expression.charAt(tokenPos) != c) + ++tokenPos; + if (tokenPos == top) { + tokenPos = start - 1; + currentToken = TOKEN_ERROR; + } else { + tokenValue = expression.substring(start, tokenPos++); + currentToken = TOKEN_LITERAL; + } + break; + } + + case '/' : { + int start = ++tokenPos; + StringBuffer buf = new StringBuffer(); + while (tokenPos < top) { + c = expression.charAt(tokenPos); + if (c == '\\' && tokenPos + 1 < top) { + c = expression.charAt(++tokenPos); + if (c != '/') + buf.append('\\'); + } else if (c == '/') + break; + buf.append(c); + ++tokenPos; + } + if (tokenPos == top) { + tokenPos = start - 1; + currentToken = TOKEN_ERROR; + } else { + tokenValue = SimplePattern.compile(expression.substring(start, tokenPos++)); + currentToken = TOKEN_LITERAL; + } + break; + } + + default : + if (Character.isDigit(c)) { + int start = tokenPos++; + while (tokenPos < top && Character.isDigit(expression.charAt(tokenPos))) + ++tokenPos; + tokenValue = Integer.valueOf(expression.substring(start, tokenPos)); + currentToken = TOKEN_LITERAL; + break; + } + if (Character.isJavaIdentifierStart(c)) { + int start = tokenPos++; + while (tokenPos < top && Character.isJavaIdentifierPart(expression.charAt(tokenPos))) + ++tokenPos; + String word = expression.substring(start, tokenPos); + if (word.equals(EachVariable.KEYWORD_EACH)) + currentToken = TOKEN_ANY; + else if (word.equals(Latest.OPERATOR)) + currentToken = TOKEN_LATEST; + else if (word.equals(Limit.OPERATOR)) + currentToken = TOKEN_LIMIT; + else if (word.equals(Unique.OPERATOR)) + currentToken = TOKEN_UNIQUE; + else if (word.equals(Select.OPERATOR)) + currentToken = TOKEN_SELECT; + else if (word.equals(Exists.OPERATOR)) + currentToken = TOKEN_EXISTS; + else if (word.equals(First.OPERATOR)) + currentToken = TOKEN_FIRST; + else if (word.equals(Flatten.OPERATOR)) + currentToken = TOKEN_FLATTEN; + else if (word.equals(All.OPERATOR)) + currentToken = TOKEN_ALL; + else if (word.equals(Reject.OPERATOR)) + currentToken = TOKEN_REJECT; + else if (word.equals(Collect.OPERATOR)) + currentToken = TOKEN_COLLECT; + else if (word.equals(Traverse.OPERATOR)) + currentToken = TOKEN_TRAVERSE; + else if (word.equals(Constant.NULL_KEYWORD)) + currentToken = TOKEN_NULL; + else if (word.equals(Constant.FALSE_KEYWORD)) + currentToken = TOKEN_FALSE; + else if (word.equals(Constant.TRUE_KEYWORD)) + currentToken = TOKEN_TRUE; + else + currentToken = TOKEN_IDENTIFIER; + tokenValue = word; + break; + } + throw syntaxError(); + } + } + + private void popVariable() { + if (isEmpty()) + throw syntaxError(); + pop(); + } + + private QueryParseException syntaxError() { + Object tv = tokenValue; + if (tv == null) { + if (lastTokenPos >= expression.length()) + return syntaxError("Unexpeced end of expression"); //$NON-NLS-1$ + tv = expression.substring(lastTokenPos, lastTokenPos + 1); + } + return syntaxError("Unexpected token \"" + tv + '"'); //$NON-NLS-1$ + } + + private QueryParseException syntaxError(String message) { + return new QueryParseException(expression, message, tokenPos); + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/FilterConstructor.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/FilterConstructor.java new file mode 100644 index 000000000..37de744ab --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/FilterConstructor.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import org.osgi.framework.InvalidSyntaxException; + +public class FilterConstructor extends Constructor { + + static final String KEYWORD = "filter"; //$NON-NLS-1$ + + public FilterConstructor(Expression[] operands) { + super(operands); + } + + Object createInstance(String arg) { + try { + return QLActivator.context.createFilter(arg); + } catch (InvalidSyntaxException e) { + throw new IllegalArgumentException(e.getMessage()); + } + } + + String getOperator() { + return KEYWORD; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/First.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/First.java new file mode 100644 index 000000000..b4d1dde18 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/First.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; + +/** + * A collection filter that yields the first element of the <code>collection</code> for which + * the <code>filter</code> yields <code>true</code> + */ +public final class First extends CollectionFilter { + public static final String OPERATOR = "first"; //$NON-NLS-1$ + + public First(Expression collection, LambdaExpression lambda) { + super(collection, lambda); + } + + Object evaluate(ExpressionContext context, VariableScope scope, Iterator itor) { + while (itor.hasNext()) { + Object each = itor.next(); + scope.setEach(variable, each); + if (lambda.evaluate(context, scope) == Boolean.TRUE) + return each; + } + return null; + } + + String getOperator() { + return OPERATOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Flatten.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Flatten.java new file mode 100644 index 000000000..1bab6cade --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Flatten.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * An expression that yields a new collection consisting of all elements of the + * <code>collection</code> for which the <code>filter</code> yields <code>true</code>. + */ +public final class Flatten extends UnaryCollectionFilter { + public static final String OPERATOR = "flatten"; //$NON-NLS-1$ + + public Flatten(Expression collection) { + super(collection); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + return new FlattenIterator(operand.evaluateAsIterator(context, scope)); + } + + String getOperator() { + return OPERATOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/FlattenIterator.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/FlattenIterator.java new file mode 100644 index 000000000..e2d659bb1 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/FlattenIterator.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * A FlattenIterator will assume that its operand is an iterator that will produce + * elements that can be represented as iterators. The elements of those iterators + * will be returned in sequence, thus removing one iterator dimension. + */ +public class FlattenIterator implements Iterator { + private static final Object NO_ELEMENT = new Object(); + private final Iterator iteratorIterator; + private Iterator currentIterator; + + private Object nextObject = NO_ELEMENT; + + public FlattenIterator(Iterator iterator) { + this.iteratorIterator = iterator; + } + + public boolean hasNext() { + return positionNext(); + } + + public Object next() { + if (!positionNext()) + throw new NoSuchElementException(); + + Object nxt = nextObject; + nextObject = NO_ELEMENT; + return nxt; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + private boolean positionNext() { + if (nextObject != NO_ELEMENT) + return true; + + while (currentIterator == null || !currentIterator.hasNext()) { + if (!iteratorIterator.hasNext()) + return false; + + Object nextItor = iteratorIterator.next(); + currentIterator = (nextItor instanceof Iterator) ? (Iterator) nextItor : RepeatableIterator.create(nextItor); + } + nextObject = currentIterator.next(); + return true; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/IRepeatableIterator.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/IRepeatableIterator.java new file mode 100644 index 000000000..7190c241f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/IRepeatableIterator.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; + +public interface IRepeatableIterator extends Iterator { + /** + * Returns a copy that will iterate over the same elements + * as this iterator. The contents or position of this iterator + * is left unchanged. + * @return A re-initialized copy of this iterator. + */ + IRepeatableIterator getCopy(); + + Object getIteratorProvider(); +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/IndexedParameter.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/IndexedParameter.java new file mode 100644 index 000000000..5308f257f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/IndexedParameter.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * An expression that picks an indexed parameter from the expression context. + */ +public final class IndexedParameter extends Parameter { + final int position; + + public IndexedParameter(int position) { + this.position = position; + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + return context.getParameter(position); + } + + public void toString(StringBuffer bld) { + bld.append('$'); + bld.append(position); + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ItemExpression.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ItemExpression.java new file mode 100644 index 000000000..3df5dc1a8 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ItemExpression.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * The item expression is the top expression in item queries. It introduces the + * variable 'item' and initializes it with the item to match. + */ +public final class ItemExpression extends Binary { + + public ItemExpression(Variable itemVariable, Expression expression) { + super(itemVariable, expression); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + return rhs.evaluate(context, scope); + } + + public boolean isMatch(ExpressionContext context, VariableScope scope, Object value) { + scope.setItem(value); + return rhs.evaluate(context, scope) == Boolean.TRUE; + } + + public void toString(StringBuffer bld) { + rhs.toString(bld); + } + + protected int getPriority() { + return rhs.getPriority(); + } + + Object evaluate(Object lval, Object rval) { + throw new UnsupportedOperationException(); + } + + String getOperator() { + throw new UnsupportedOperationException(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ItemVariable.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ItemVariable.java new file mode 100644 index 000000000..c3a01e4ef --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ItemVariable.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * An expression representing a variable stack in the current thread. + */ +final class ItemVariable extends Variable { + + ItemVariable(String name) { + super(name); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + return scope.getItem(); + } + + int countReferenceToEverything() { + return 0; + } + + void setValue(VariableScope scope, Object value) { + scope.setItem(value); + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/KeyedParameter.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/KeyedParameter.java new file mode 100644 index 000000000..dd8acc2e5 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/KeyedParameter.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * An expression that picks an keyed parameter from the expression context. + */ +public final class KeyedParameter extends Parameter { + final String key; + + public KeyedParameter(String key) { + this.key = key; + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + return context.getParameter(key); + } + + public void toString(StringBuffer bld) { + bld.append('$'); + bld.append(key); + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LambdaExpression.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LambdaExpression.java new file mode 100644 index 000000000..4d9e99565 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LambdaExpression.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * A function that executes some code + */ +public final class LambdaExpression extends Unary { + private final Expression[] currying; + private final Variable[] variables; + + public LambdaExpression(Expression body, Expression[] currying, Variable[] variables) { + super(body); + int idx = currying.length; + if (idx > 0) { + if (idx != variables.length) + throw new IllegalArgumentException("Number of currying expressions and variables differ"); //$NON-NLS-1$ + int anyCount = 0; + while (--idx >= 0) + if (currying[idx] instanceof EachVariable) + ++anyCount; + if (anyCount != 1) + throw new IllegalArgumentException("Exaclty one _ must be present among the currying expressions"); //$NON-NLS-1$ + } else if (variables.length != 1) + throw new IllegalArgumentException("Exaclty one variable required unless currying is used"); //$NON-NLS-1$ + this.currying = currying; + this.variables = variables; + } + + public LambdaExpression(Expression body, Variable variable) { + this(body, Expression.emptyArray, new Variable[] {variable}); + } + + public boolean accept(Visitor visitor) { + if (super.accept(visitor)) { + for (int idx = 0; idx < currying.length; ++idx) + if (!currying[idx].accept(visitor)) + return false; + for (int idx = 0; idx < variables.length; ++idx) + if (!variables[idx].accept(visitor)) + return false; + } + return true; + } + + public void toString(StringBuffer bld) { + int top = currying.length; + if (top > 0) { + Array.elementsToString(bld, currying); + bld.append(", {"); //$NON-NLS-1$ + } + Array.elementsToString(bld, variables); + bld.append(" | "); //$NON-NLS-1$ + appendOperand(bld, operand, ExpressionParser.PRIORITY_COMMA); + if (top > 0) + bld.append('}'); + } + + int countReferenceToEverything() { + if (super.countReferenceToEverything() > 0) + return 2; + for (int idx = 0; idx < currying.length; ++idx) + if (currying[idx].countReferenceToEverything() > 0) + return 2; + for (int idx = 0; idx < variables.length; ++idx) + if (variables[idx].countReferenceToEverything() > 0) + return 2; + return 0; + } + + EachVariable getItemVariable() { + int idx = currying.length; + if (idx == 0) + // No currying. Then we know that we have exactly one variable + return (EachVariable) variables[0]; + + while (--idx >= 0) { + Expression expr = currying[idx]; + if (expr instanceof EachVariable) + return (EachVariable) variables[idx]; + } + return null; + } + + String getOperator() { + return "|"; //$NON-NLS-1$ + } + + int getPriority() { + return ExpressionParser.PRIORITY_LAMBDA; + } + + VariableScope prolog(ExpressionContext context, VariableScope scope) { + VariableScope lambdaScope = new VariableScope(scope); + for (int idx = 0; idx < currying.length; ++idx) { + Expression curry = currying[idx]; + if (!(curry instanceof EachVariable)) + variables[idx].setValue(lambdaScope, curry.evaluate(context, scope)); + } + return lambdaScope; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Latest.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Latest.java new file mode 100644 index 000000000..5f5dac1cb --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Latest.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.IVersionedId; + +/** + * An expression that is especially targeted towards {@link IVersionedId} instances. It will + * reject any objects that is not an <code>IVersionedId</code> and it will ensure that the + * resulting iterator only iterates over the latest version of any found id. + */ +public final class Latest extends UnaryCollectionFilter { + + static final String OPERATOR = "latest"; //$NON-NLS-1$ + + public Latest(Expression collection) { + super(collection); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + Class instanceClass = context.getInstanceClass(); + if (!IVersionedId.class.isAssignableFrom(instanceClass)) + return Collections.EMPTY_SET.iterator(); + + HashMap greatestIUVersion; + if (operand instanceof Select) { + // Inline element evaluation here so that we don't build a map that is + // larger then it has to be + Select select = (Select) operand; + Iterator iterator = select.operand.evaluateAsIterator(context, scope); + if (!iterator.hasNext()) + return Collections.EMPTY_SET.iterator(); + + greatestIUVersion = new HashMap(); + while (iterator.hasNext()) { + Object next = iterator.next(); + if (!instanceClass.isInstance(next)) + continue; + + select.variable.setValue(scope, next); + if (select.lambda.evaluate(context, scope) != Boolean.TRUE) + continue; + + IVersionedId versionedID = (IVersionedId) next; + String id = versionedID.getId(); + IVersionedId prev = (IVersionedId) greatestIUVersion.put(id, versionedID); + if (prev == null) + continue; + if (prev.getVersion().compareTo(versionedID.getVersion()) > 0) + greatestIUVersion.put(id, prev); + } + } else { + Iterator iterator = operand.evaluateAsIterator(context, scope); + if (iterator == null) + return null; + if (!iterator.hasNext()) + return Collections.EMPTY_SET.iterator(); + + greatestIUVersion = new HashMap(); + while (iterator.hasNext()) { + Object next = iterator.next(); + if (!instanceClass.isInstance(next)) + continue; + + IVersionedId versionedID = (IVersionedId) next; + String id = versionedID.getId(); + + IVersionedId prev = (IVersionedId) greatestIUVersion.put(id, versionedID); + if (prev == null) + continue; + + if (prev.getVersion().compareTo(versionedID.getVersion()) > 0) + greatestIUVersion.put(id, prev); + } + } + return greatestIUVersion.values().iterator(); + } + + String getOperator() { + return OPERATOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Limit.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Limit.java new file mode 100644 index 000000000..d93a9d390 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Limit.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * A collection filter that limits the number of entries in the collection + */ +public final class Limit extends Binary { + + /** + * An iterator that stops iterating after a given number of iterations. + */ + public static final class CountingIterator implements Iterator { + private final Iterator innerIterator; + private int counter; + + public CountingIterator(Iterator iterator, int count) { + this.innerIterator = iterator; + this.counter = count; + } + + public boolean hasNext() { + return counter > 0 && innerIterator.hasNext(); + } + + public Object next() { + if (counter > 0) { + --counter; + return innerIterator.next(); + } + throw new NoSuchElementException(); + } + + public void remove() { + innerIterator.remove(); + } + } + + static final String OPERATOR = "limit"; //$NON-NLS-1$ + + public Limit(Expression operand, Expression param) { + super(operand, param); + } + + public Limit(Expression operand, int limit) { + this(operand, new Constant(new Integer(limit))); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + Object rval = rhs.evaluate(context, scope); + int limit = -1; + if (rval instanceof Integer) + limit = ((Integer) rval).intValue(); + if (limit <= 0) + throw new IllegalArgumentException("limit expression did not evalutate to a positive integer"); //$NON-NLS-1$ + return new CountingIterator(lhs.evaluateAsIterator(context, scope), limit); + } + + public void toString(StringBuffer bld) { + CollectionFilter.appendProlog(bld, lhs, getOperator()); + appendOperand(bld, rhs, ExpressionParser.PRIORITY_COMMA); + bld.append(')'); + } + + String getOperator() { + return OPERATOR; + } + + int getPriority() { + return ExpressionParser.PRIORITY_COLLECTION; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LocalizedKeys.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LocalizedKeys.java new file mode 100644 index 000000000..764571492 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LocalizedKeys.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.ArrayList; +import java.util.Locale; + +public class LocalizedKeys extends Constructor { + static final String KEYWORD = "localizedKeys"; //$NON-NLS-1$ + + public LocalizedKeys(Expression[] operands) { + super(operands); + int argCount = operands.length; + if (argCount != 2) + throw new IllegalArgumentException("localizedKeys must have exactly two arguments. The Locale and the key"); //$NON-NLS-1$ + } + + public synchronized Object evaluate(ExpressionContext context, VariableScope scope) { + Object arg = operands[0].evaluate(context, scope); + if (!(arg instanceof Locale)) + throw new IllegalArgumentException("localizedKeys first argument must be a java.util.Locale"); //$NON-NLS-1$ + Locale locale = (Locale) arg; + + arg = operands[1].evaluate(context, scope); + if (!(arg instanceof String)) + throw new IllegalArgumentException("localizedKeys second argument must be a string"); //$NON-NLS-1$ + String key = (String) arg; + + ArrayList keyList = new ArrayList(); + StringBuffer bld = new StringBuffer(); + bld.append(locale.getLanguage()); + int pos = bld.length(); + bld.append('.'); + bld.append(key); + keyList.add(bld.toString()); + bld.setLength(pos); + + bld.append('_'); + if (locale.getCountry().length() > 0) { + bld.append(locale.getCountry()); + pos = bld.length(); + bld.append('.'); + bld.append(key); + keyList.add(bld.toString()); + bld.setLength(pos); + } + + if (locale.getVariant().length() > 0) { + bld.append('_'); + bld.append(locale.getVariant()); + bld.append('.'); + bld.append(key); + keyList.add(bld.toString()); + } + bld.setLength(0); + bld.append("df_LT."); //$NON-NLS-1$ + bld.append(key); + keyList.add(bld.toString()); + return keyList.toArray(new String[keyList.size()]); + } + + String getOperator() { + return KEYWORD; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LocalizedMap.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LocalizedMap.java new file mode 100644 index 000000000..e027b8a80 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LocalizedMap.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.*; + +public final class LocalizedMap extends Constructor { + + static final String KEYWORD = "localizedMap"; //$NON-NLS-1$ + + private static final WeakHashMap localizedMapCache = new WeakHashMap(); + + private static final ContextExpression localizedPropertiesExpr = new ExpressionParser().parseQuery("" + // //$NON-NLS-1$ + "everything.select(f | f ~= $2 &&" + // //$NON-NLS-1$ + " f.host.exists(h | $0 ~= h) &&" + // //$NON-NLS-1$ + " f.providedCapabilities.exists(pc | pc.namespace == 'org.eclipse.equinox.p2.localization' && pc.name ~= $1))" + // //$NON-NLS-1$ + ".collect(f | f.properties).flatten()"); //$NON-NLS-1$ + + public LocalizedMap(Expression[] operands) { + super(operands); + if (operands.length != 2) + throw new IllegalArgumentException(KEYWORD + " must have exactly two arguments. The Locale and the IU"); //$NON-NLS-1$ + } + + public synchronized Object evaluate(ExpressionContext context, VariableScope scope) { + Object arg = operands[0].evaluate(context, scope); + if (!(arg instanceof Locale)) + throw new IllegalArgumentException(KEYWORD + " first argument must be a java.util.Locale"); //$NON-NLS-1$ + Locale locale = (Locale) arg; + + arg = operands[1].evaluate(context, scope); + if (!(arg instanceof IInstallableUnit)) + throw new IllegalArgumentException(KEYWORD + " second argument must be an IInstallableUnit"); //$NON-NLS-1$ + + IInstallableUnit iu = (IInstallableUnit) arg; + if (iu instanceof IInstallableUnitFragment) { + // Check that this isn't a translation fragment in itself. + IProvidedCapability[] provides = iu.getProvidedCapabilities(); + int idx = provides.length; + while (--idx >= 0) { + IProvidedCapability pc = provides[idx]; + if (pc.getNamespace().equals("org.eclipse.equinox.p2.localization")) //$NON-NLS-1$ + return Collections.EMPTY_MAP; + } + } + + Map iuLocales; + synchronized (localizedMapCache) { + iuLocales = (Map) localizedMapCache.get(iu); + if (iuLocales == null) { + iuLocales = new HashMap(); + localizedMapCache.put(iu, iuLocales); + } + } + + Map properties; + synchronized (iuLocales) { + properties = (Map) iuLocales.get(locale); + if (properties == null) { + properties = new HashMap(); + collectLocaleProperties(context, scope, locale, iu, properties); + iuLocales.put(locale, properties); + } + } + return properties; + } + + int countReferenceToEverything() { + return 1; + } + + private static void collectLocaleProperties(ExpressionContext context, VariableScope scope, Locale locale, IInstallableUnit iu, Map properties) { + List localePrefixes = getLocalePrefixes(locale); + addPrefixedProperties(localePrefixes, properties, iu.getProperties().entrySet().iterator()); + ExpressionContext subContext = new ExpressionContext(IInstallableUnitFragment.class, new Object[] {iu, locale, IInstallableUnitFragment.class}, context.getCopy(), false); + addPrefixedProperties(localePrefixes, properties, localizedPropertiesExpr.evaluateAsIterator(subContext, new VariableScope())); + } + + private static void addPrefixedProperties(List prefixes, Map properties, Iterator entries) { + int prefixCount = prefixes.size(); + outer: while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + String key = (String) entry.getKey(); + for (int idx = 0; idx < prefixCount; ++idx) { + if (key.startsWith((String) prefixes.get(idx))) { + properties.put(key, entry.getValue()); + continue outer; + } + } + } + } + + private static List getLocalePrefixes(Locale locale) { + ArrayList keyList = new ArrayList(); + + StringBuffer bld = new StringBuffer(); + bld.append(locale.getLanguage()); + int pos = bld.length(); + bld.append('.'); + keyList.add(bld.toString()); + bld.setLength(pos); + + bld.append('_'); + if (locale.getCountry().length() > 0) { + bld.append(locale.getCountry()); + pos = bld.length(); + bld.append('.'); + keyList.add(bld.toString()); + bld.setLength(pos); + } + + if (locale.getVariant().length() > 0) { + bld.append('_'); + bld.append(locale.getVariant()); + bld.append('.'); + keyList.add(bld.toString()); + } + keyList.add("df_LT."); //$NON-NLS-1$ + return keyList; + } + + String getOperator() { + return KEYWORD; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LocalizedProperty.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LocalizedProperty.java new file mode 100644 index 000000000..9d8db902e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LocalizedProperty.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; +import java.util.Map; + +public final class LocalizedProperty extends Constructor { + + static final String KEYWORD = "localizedProperty"; //$NON-NLS-1$ + + private static ContextExpression localePropertiesExpr = new ExpressionParser().parseQuery("" + // //$NON-NLS-1$ + "localizedMap($0, $1).select(e | localizedKeys($0, $2).exists(k | k == e.key))"); //$NON-NLS-1$ + + public LocalizedProperty(Expression[] operands) { + super(operands); + if (operands.length != 3) + throw new IllegalArgumentException(KEYWORD + " must have exactly three arguments. The Locale, IU, and key"); //$NON-NLS-1$ + } + + public synchronized Object evaluate(ExpressionContext context, VariableScope scope) { + Object[] args = new Object[] {operands[0].evaluate(context, scope), operands[1].evaluate(context, scope), operands[2].evaluate(context, scope)}; + ExpressionContext subContext = new ExpressionContext(Map.Entry.class, args, context, false); + Iterator itor = localePropertiesExpr.evaluateAsIterator(subContext, new VariableScope()); + return itor.hasNext() ? ((Map.Entry) itor.next()).getValue() : null; + } + + int countReferenceToEverything() { + return 1; // Since we use a LocalizedMap + } + + String getOperator() { + return KEYWORD; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/MatchIteratorFilter.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/MatchIteratorFilter.java new file mode 100644 index 000000000..b8cfe2f75 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/MatchIteratorFilter.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * An iterator filter using a boolean {@link #isMatch(Object)} method. + */ +public abstract class MatchIteratorFilter implements Iterator { + private static final Object NO_ELEMENT = new Object(); + + private final Iterator innerIterator; + + private final Class instanceClass; + + private Object nextObject = NO_ELEMENT; + + public MatchIteratorFilter(Class instanceClass, Iterator iterator) { + this.instanceClass = instanceClass; + this.innerIterator = iterator; + } + + public boolean hasNext() { + return positionNext(); + } + + public Object next() { + if (!positionNext()) + throw new NoSuchElementException(); + + Object nxt = nextObject; + nextObject = NO_ELEMENT; + return nxt; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + protected abstract boolean isMatch(Object val); + + private boolean positionNext() { + if (nextObject != NO_ELEMENT) + return true; + + while (innerIterator.hasNext()) { + Object nxt = innerIterator.next(); + if (instanceClass.isInstance(nxt) && isMatch(nxt)) { + nextObject = nxt; + return true; + } + } + return false; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Matches.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Matches.java new file mode 100644 index 000000000..5171a477a --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Matches.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.*; +import org.osgi.framework.Filter; + +/** + * <p>A class that performs "matching" The actual algorithm used for + * performing the match varies depending on the types of the items to match.</p> + * <p>The following things can be matched:</p> + * <table border="1" cellpadding="3"> + * <tr><th>LHS</th><th>RHS</th><th>Implemented as</th></tr> + * <tr><td>IProvidedCapability</td><td>IRequiredCapability</td><td>lhs.satisfies(rhs)</td></tr> + * <tr><td>IInstallableUnit</td><td>IRequiredCapability</td><td>lhs.satisfies(rhs)</td></tr> + * <tr><td>Version</td><td>VersionRange</td><td>rhs.isIncluded(lhs)</td></tr> + * <tr><td>IInstallableUnit</td><td>Filter</td><td>rhs.matches(lhs.properties)</td></tr> + * <tr><td>Map</td><td>Filter</td><td>rhs.match(lhs)</td></tr> + * <tr><td>String</td><td>Pattern</td><td>rhs.matcher(lhs).matches()</td></tr> + * <tr><td><any></td><td>Class</td><td>rhs.isInstance(lhs)</td></tr> + * <tr><td>Class</td><td>Class</td><td>rhs.isAssignableFrom(lhs)</td></tr> + * </table> + */ +public final class Matches extends Binary { + public static final String OPERATOR = "~="; //$NON-NLS-1$ + + public Matches(Expression lhs, Expression rhs) { + super(lhs, rhs); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + Object lval = lhs.evaluate(context, scope); + Object rval = rhs.evaluate(context, scope); + + if (rval instanceof IRequiredCapability) { + IRequiredCapability cap = (IRequiredCapability) rval; + if (lval instanceof IInstallableUnit) + return Boolean.valueOf(((IInstallableUnit) lval).satisfies(cap)); + if (lval instanceof IProvidedCapability) + return Boolean.valueOf(((IProvidedCapability) lval).satisfies(cap)); + + } else if (rval instanceof VersionRange) { + if (lval instanceof Version) + return Boolean.valueOf(((VersionRange) rval).isIncluded((Version) lval)); + + } else if (rval instanceof SimplePattern) { + if (lval instanceof CharSequence) + return Boolean.valueOf(((SimplePattern) rval).isMatch((CharSequence) lval)); + + } else if (rval instanceof IUpdateDescriptor) { + if (lval instanceof IInstallableUnit) + return Boolean.valueOf(((IUpdateDescriptor) rval).isUpdateOf((IInstallableUnit) lval)); + + } else if (rval instanceof Filter) { + if (lval instanceof IInstallableUnit) + return Boolean.valueOf(((Filter) rval).match(new Hashtable(((IInstallableUnit) lval).getProperties()))); + if (lval instanceof Dictionary) + return Boolean.valueOf(((Filter) rval).match((Dictionary) lval)); + if (lval instanceof Map) + return Boolean.valueOf(((Filter) rval).match(new Hashtable((Map) lval))); + + } else if (rval instanceof Locale) { + if (lval instanceof String) + return Boolean.valueOf(matchLocaleVariants((Locale) rval, (String) lval)); + + } else if (rval instanceof Class) { + Class rclass = (Class) rval; + return Boolean.valueOf(lval instanceof Class ? rclass.isAssignableFrom((Class) lval) : rclass.isInstance(lval)); + } + + if (lval == null || rval == null) + return Boolean.FALSE; + + throw new IllegalArgumentException("Cannot match a " + lval.getClass().getName() + " with a " + rval.getClass().getName()); //$NON-NLS-1$//$NON-NLS-2$ + } + + private static boolean equals(String a, String b, int startPos, int endPos) { + if (endPos - startPos != b.length()) + return false; + + int bidx = 0; + while (startPos < endPos) + if (a.charAt(startPos++) != b.charAt(bidx++)) + return false; + return true; + } + + private static boolean matchLocaleVariants(Locale rval, String lval) { + int uscore = lval.indexOf('_'); + if (uscore < 0) + // No country and no variant. Just match language + return lval.equals(rval.getLanguage()); + + if (!equals(lval, rval.getLanguage(), 0, uscore)) + // Language part doesn't match. Give up. + return false; + + // Check country and variant + int countryStart = uscore + 1; + uscore = lval.indexOf('_', countryStart); + return uscore < 0 ? equals(lval, rval.getCountry(), countryStart, lval.length()) // + : equals(lval, rval.getCountry(), countryStart, uscore) && equals(lval, rval.getVariant(), uscore + 1, lval.length()); + } + + String getOperator() { + return OPERATOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Member.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Member.java new file mode 100644 index 000000000..eb2854884 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Member.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.lang.reflect.*; + +/** + * <p>An expression that performs member calls to obtain some value + * from some object instance. It uses standard bean semantics so + * that an attempt to obtain "value" will cause an + * attempt to call <code>getValue()</code> and if no such method + * exists, <code>isValue()</code> and if that doesn't work either, + * <code>value()</code>.</p> + */ +public final class Member extends Unary { + static final String OPERATOR = "."; //$NON-NLS-1$ + + private static final Class[] NO_ARG_TYPES = new Class[0]; + private static final Object[] NO_ARGS = new Object[0]; + private static final String GET_PREFIX = "get"; //$NON-NLS-1$ + private static final String IS_PREFIX = "is"; //$NON-NLS-1$ + + protected final String name; + + private String methodName; + private Class lastClass; + private Method method; + + public Member(Expression operand, String name) { + super(operand); + this.name = name; + + if (!(name.startsWith(GET_PREFIX) || name.startsWith(IS_PREFIX))) + name = GET_PREFIX + Character.toUpperCase(name.charAt(0)) + name.substring(1); + this.methodName = name; + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + Object value = operand.evaluate(context, scope); + if (value == null) + throw new IllegalArgumentException("Cannot access member " + name + " in null"); //$NON-NLS-1$//$NON-NLS-2$ + return invoke(value); + } + + public void toString(StringBuffer bld) { + if (operand == Variable.ITEM || operand == Variable.EVERYTHING) + bld.append(name); + else { + appendOperand(bld, operand, getPriority()); + bld.append('.'); + bld.append(name); + } + } + + String getOperator() { + return OPERATOR; + } + + int getPriority() { + return ExpressionParser.PRIORITY_MEMBER; + } + + Object invoke(Object value) { + Class c = value.getClass(); + if (lastClass == null || !lastClass.isAssignableFrom(c)) { + Method m; + for (;;) { + try { + m = c.getMethod(methodName, NO_ARG_TYPES); + if (!Modifier.isPublic(m.getModifiers())) + throw new NoSuchMethodException(); + break; + } catch (NoSuchMethodException e) { + if (methodName.startsWith(GET_PREFIX)) + // Switch from using getXxx() to isXxx() + methodName = IS_PREFIX + Character.toUpperCase(name.charAt(0)) + name.substring(1); + else if (methodName.startsWith(IS_PREFIX)) + // Switch from using isXxx() to xxx() + methodName = name; + else + throw new IllegalArgumentException("Cannot find a public member " + name + " in a " + value.getClass().getName()); //$NON-NLS-1$//$NON-NLS-2$ + } + } + + // Since we already checked that it's public. This will speed + // up the calls a bit. + m.setAccessible(true); + lastClass = c; + method = m; + } + + Exception checked; + try { + return method.invoke(value, NO_ARGS); + } catch (IllegalArgumentException e) { + throw e; + } catch (IllegalAccessException e) { + checked = e; + } catch (InvocationTargetException e) { + Throwable cause = e.getTargetException(); + if (cause instanceof RuntimeException) + throw (RuntimeException) cause; + if (cause instanceof Error) + throw (Error) cause; + checked = (Exception) cause; + } + throw new RuntimeException("Problem invoking " + methodName + " on a " + value.getClass().getName(), checked); //$NON-NLS-1$ //$NON-NLS-2$ + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/NAry.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/NAry.java new file mode 100644 index 000000000..b010c5be6 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/NAry.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * The abstract baseclass for all N-ary expressions + * + */ +abstract class NAry extends Expression { + static Expression[] assertLength(Expression[] operands, int length, String operand) { + if (operands == null) + operands = emptyArray; + if (operands.length < length) + throw new IllegalArgumentException("Not enough operands for " + operand); //$NON-NLS-1$ + return operands; + } + + final Expression[] operands; + + NAry(Expression[] operands) { + this.operands = operands; + } + + public boolean accept(Visitor visitor) { + if (super.accept(visitor)) + for (int idx = 0; idx < operands.length; ++idx) + if (!operands[idx].accept(visitor)) + return false; + return true; + } + + public void toString(StringBuffer bld) { + appendOperand(bld, operands[0], getPriority()); + for (int idx = 1; idx < operands.length; ++idx) { + bld.append(' '); + bld.append(getOperator()); + bld.append(' '); + appendOperand(bld, operands[idx], getPriority()); + } + } + + int countReferenceToEverything() { + int count = 0; + for (int idx = 0; count < 2 && idx < operands.length; ++idx) + count += operands[idx].countReferenceToEverything(); + return count; + } + + abstract String getOperator(); +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Not.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Not.java new file mode 100644 index 000000000..6e2bc7048 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Not.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * An expression that yields <code>true</code> when its operand does not. + */ +public final class Not extends Unary { + public static final String OPERATOR = "!"; //$NON-NLS-1$ + + public Not(Expression operand) { + super(operand); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + return Boolean.valueOf(operand.evaluate(context, scope) != Boolean.TRUE); + } + + String getOperator() { + return OPERATOR; + } + + int getPriority() { + return ExpressionParser.PRIORITY_NOT; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Or.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Or.java new file mode 100644 index 000000000..25bf9d441 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Or.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; +import java.util.Set; + +/** + * n-ary OR operator. This operator evaluates its first operand and then checks + * the class of the result. If the class is {@link Boolean} then it is assumed + * that all other operands also evaluates to a boolean and the full evaluation is + * <code>false</code> if none of its operands evaluate to <code>true</code>. If the + * first result was not of class {@link Boolean}, then it is assumed that it can + * be accessed as an {@link Iterator} and that all other operands also evaluates to + * something that can be accessed an {@link Iterator}. The OR operator will then + * function as a UNION operator and the result is the unique sum of all elements that + * were found in all operands. + */ +public final class Or extends NAry { + public static final String OPERATOR = "||"; //$NON-NLS-1$ + + public Or(Expression[] operands) { + super(assertLength(operands, 2, OPERATOR)); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + Object firstValue = operands[0].evaluate(context, scope); + + // Determine operation mode + if (firstValue instanceof Boolean) { + // The first value was boolean. Assume that the rest are too + if (((Boolean) firstValue).booleanValue()) + return Boolean.TRUE; + + for (int idx = 1; idx < operands.length; ++idx) { + if (operands[idx].evaluate(context, scope) == Boolean.TRUE) + return Boolean.TRUE; + } + return Boolean.FALSE; + } + + // Not a boolean. Assume that we can use an iterator on all values + Set resultSet = asSet(firstValue, true); + for (int idx = 1; idx < operands.length; ++idx) { + Iterator itor = operands[idx].evaluateAsIterator(context, scope); + while (itor.hasNext()) + resultSet.add(itor.next()); + } + return resultSet; + } + + String getOperator() { + return OPERATOR; + } + + int getPriority() { + return ExpressionParser.PRIORITY_OR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Parameter.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Parameter.java new file mode 100644 index 000000000..0e96513f7 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Parameter.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * The abstract base class for the indexed and keyed parameters + */ +abstract class Parameter extends Expression { + static final String OPERATOR = "$"; //$NON-NLS-1$ + + int getPriority() { + return ExpressionParser.PRIORITY_PARAMETER; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/QLActivator.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/QLActivator.java new file mode 100644 index 000000000..d1fc901fd --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/QLActivator.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class QLActivator implements BundleActivator { + public static BundleContext context; + + public static BundleContext getContext() { + return context; + } + + public void start(BundleContext aContext) throws Exception { + QLActivator.context = aContext; + } + + public void stop(BundleContext aContext) throws Exception { + QLActivator.context = null; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/QueryParseException.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/QueryParseException.java new file mode 100644 index 000000000..50b32ce70 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/QueryParseException.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +public class QueryParseException extends RuntimeException { + private static final long serialVersionUID = -4834995551702455870L; + + public QueryParseException(String expression, String message, int position) { + super("Parse error in string \"" + expression + "\": " + message + " at position " + position); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/RangeConstructor.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/RangeConstructor.java new file mode 100644 index 000000000..fa8662049 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/RangeConstructor.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import org.eclipse.equinox.internal.provisional.p2.metadata.VersionRange; + +public class RangeConstructor extends Constructor { + + static final String KEYWORD = "range"; //$NON-NLS-1$ + + public RangeConstructor(Expression[] operands) { + super(operands); + } + + Object createInstance(String arg) { + return new VersionRange(arg); + } + + String getOperator() { + return KEYWORD; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Reject.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Reject.java new file mode 100644 index 000000000..a652b5a7e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Reject.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; + +/** + * An expression that yields a new collection consisting of all elements of the + * <code>collection</code> for which the <code>filter</code> does not yield <code>true</code>. + */ +public class Reject extends CollectionFilter { + public static final String OPERATOR = "reject"; //$NON-NLS-1$ + + public Reject(Expression collection, LambdaExpression lambda) { + super(collection, lambda); + } + + Object evaluate(final ExpressionContext context, final VariableScope scope, Iterator iterator) { + return new MatchIteratorFilter(Object.class, iterator) { + protected boolean isMatch(Object val) { + scope.setEach(variable, val); + return lambda.evaluate(context, scope) != Boolean.TRUE; + } + }; + } + + protected String getOperator() { + return OPERATOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/RepeatableIterator.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/RepeatableIterator.java new file mode 100644 index 000000000..e1419e9a9 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/RepeatableIterator.java @@ -0,0 +1,236 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.query.Collector; + +public class RepeatableIterator implements IRepeatableIterator { + private final List values; + private int position = -1; + + public static IRepeatableIterator create(Object unknown) { + if (unknown.getClass().isArray()) + return create((Object[]) unknown); + if (unknown instanceof Iterator) + return create((Iterator) unknown); + if (unknown instanceof List) + return create((List) unknown); + if (unknown instanceof Collection) + return create((Collection) unknown); + if (unknown instanceof Map) + return create(((Map) unknown).entrySet()); + if (unknown instanceof Collector) + return create((Collector) unknown); + throw new IllegalArgumentException("Cannot convert a " + unknown.getClass().getName() + " into an iterator"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public static IRepeatableIterator create(Iterator iterator) { + return iterator instanceof IRepeatableIterator ? ((IRepeatableIterator) iterator).getCopy() : new ElementRetainingIterator(iterator); + } + + public static IRepeatableIterator create(List values) { + return new RepeatableIterator(values); + } + + public static IRepeatableIterator create(Collection values) { + return new CollectionIterator(values); + } + + public static IRepeatableIterator create(Collector values) { + return new CollectorIterator(values); + } + + public static IRepeatableIterator create(Object[] values) { + return new ArrayIterator(values); + } + + RepeatableIterator(List values) { + this.values = values; + } + + public IRepeatableIterator getCopy() { + return new RepeatableIterator(values); + } + + public boolean hasNext() { + return position + 1 < values.size(); + } + + public Object next() { + if (++position == values.size()) { + --position; + throw new NoSuchElementException(); + } + return values.get(position); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public Object getIteratorProvider() { + return values; + } + + void setPosition(int position) { + this.position = position; + } + + List getValues() { + return values; + } + + static class ArrayIterator implements IRepeatableIterator { + private final Object[] array; + private int position = -1; + + public ArrayIterator(Object[] array) { + this.array = array; + } + + public Object getIteratorProvider() { + return array; + } + + public boolean hasNext() { + return position + 1 < array.length; + } + + public Object next() { + if (++position >= array.length) + throw new NoSuchElementException(); + return array[position]; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public IRepeatableIterator getCopy() { + return new ArrayIterator(array); + } + } + + static class CollectionIterator implements IRepeatableIterator { + private final Collection collection; + + private final Iterator iterator; + + CollectionIterator(Collection collection) { + this.collection = collection; + this.iterator = collection.iterator(); + } + + public IRepeatableIterator getCopy() { + return new CollectionIterator(collection); + } + + public Object getIteratorProvider() { + return collection; + } + + public boolean hasNext() { + return iterator.hasNext(); + } + + public Object next() { + return iterator.next(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + static class CollectorIterator implements IRepeatableIterator { + private final Collector collector; + + private final Iterator iterator; + + CollectorIterator(Collector collector) { + this.collector = collector; + this.iterator = collector.iterator(); + } + + public IRepeatableIterator getCopy() { + return new CollectorIterator(collector); + } + + public Object getIteratorProvider() { + return collector; + } + + public boolean hasNext() { + return iterator.hasNext(); + } + + public Object next() { + return iterator.next(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + static class ElementRetainingIterator extends RepeatableIterator { + + private Iterator innerIterator; + + ElementRetainingIterator(Iterator iterator) { + super(new ArrayList()); + innerIterator = iterator; + } + + public synchronized boolean hasNext() { + if (innerIterator != null) { + if (innerIterator.hasNext()) + return true; + innerIterator = null; + setPosition(getValues().size()); + } + return super.hasNext(); + } + + public synchronized Object next() { + if (innerIterator != null) { + Object val = innerIterator.next(); + getValues().add(val); + return val; + } + return super.next(); + } + + public synchronized IRepeatableIterator getCopy() { + // If the current iterator still exists, we must exhaust it first + // + exhaustInnerIterator(); + return super.getCopy(); + } + + public synchronized Object getIteratorProvider() { + exhaustInnerIterator(); + return super.getIteratorProvider(); + } + + private void exhaustInnerIterator() { + if (innerIterator != null) { + List values = getValues(); + int savePos = values.size() - 1; + while (innerIterator.hasNext()) + values.add(innerIterator.next()); + innerIterator = null; + setPosition(savePos); + } + } + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Select.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Select.java new file mode 100644 index 000000000..aceee97b0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Select.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; + +/** + * An expression that yields a new collection consisting of all elements of the + * <code>collection</code> for which the <code>filter</code> yields <code>true</code>. + */ +public final class Select extends CollectionFilter { + public static final String OPERATOR = "select"; //$NON-NLS-1$ + + public Select(Expression collection, LambdaExpression lambda) { + super(collection, lambda); + } + + Object evaluate(final ExpressionContext context, final VariableScope scope, Iterator iterator) { + return new MatchIteratorFilter(Object.class, iterator) { + protected boolean isMatch(Object val) { + scope.setEach(variable, val); + return lambda.evaluate(context, scope) == Boolean.TRUE; + } + }; + } + + String getOperator() { + return OPERATOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/SetConstructor.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/SetConstructor.java new file mode 100644 index 000000000..5488f397b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/SetConstructor.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.HashSet; + +public class SetConstructor extends Constructor { + + static final String KEYWORD = "set"; //$NON-NLS-1$ + + public SetConstructor(Expression[] operands) { + super(operands); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + HashSet result = new HashSet(); + for (int idx = 0; idx < operands.length; ++idx) + result.add(operands[idx].evaluate(context, scope)); + return result; + } + + String getOperator() { + return KEYWORD; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/SimplePattern.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/SimplePattern.java new file mode 100644 index 000000000..035489b3a --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/SimplePattern.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +public class SimplePattern { + private static class RubberBandNode extends Node { + RubberBandNode(Node next) { + super(next); + } + + boolean match(CharSequence value, int pos) { + if (next == null) + return true; + + int top = value.length(); + while (pos < top) { + if (next.match(value, pos++)) + return true; + } + return false; + } + } + + private static class AnyCharacterNode extends Node { + AnyCharacterNode(Node next) { + super(next); + } + + boolean match(CharSequence value, int pos) { + int top = value.length(); + return next == null ? pos + 1 == top : next.match(value, pos + 1); + } + } + + private static class ConstantNode extends Node { + final String constant; + + ConstantNode(Node next, String constant) { + super(next); + this.constant = constant; + } + + boolean match(CharSequence value, int pos) { + int vtop = value.length(); + int ctop = constant.length(); + if (ctop + pos > vtop) + return false; + + for (int idx = 0; idx < ctop; ++idx, ++pos) + if (constant.charAt(idx) != value.charAt(pos)) + return false; + + return next == null ? true : next.match(value, pos); + } + } + + private static abstract class Node { + final Node next; + + Node(Node next) { + this.next = next; + } + + abstract boolean match(CharSequence value, int pos); + } + + public static SimplePattern compile(String pattern) { + if (pattern == null) + throw new IllegalArgumentException("Pattern can not be null"); //$NON-NLS-1$ + + return new SimplePattern(parse(pattern, 0)); + } + + private static Node parse(String pattern, int pos) { + int top = pattern.length(); + StringBuffer bld = null; + Node parsedNode = null; + while (pos < top) { + char c = pattern.charAt(pos); + switch (c) { + case '*' : + parsedNode = new RubberBandNode(parse(pattern, pos + 1)); + break; + case '?' : + parsedNode = new AnyCharacterNode(parse(pattern, pos + 1)); + break; + case '\\' : + if (++pos == top) + throw new IllegalArgumentException("Pattern ends with escape"); //$NON-NLS-1$ + c = pattern.charAt(pos); + // fall through + default : + if (bld == null) + bld = new StringBuffer(); + bld.append(c); + ++pos; + continue; + } + break; + } + + if (bld != null) + parsedNode = new ConstantNode(parsedNode, bld.toString()); + return parsedNode; + } + + private final Node node; + + private SimplePattern(Node node) { + this.node = node; + } + + public boolean isMatch(CharSequence value) { + return node.match(value, 0); + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Traverse.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Traverse.java new file mode 100644 index 000000000..693f74cf6 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Traverse.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.*; + +/** + * An expression that will collect items recursively based on a <code>rule</code>. + * The <code>rule</code> is applied for each item in the <code>collection</code> and + * is supposed to create a new collection. The <code>rule</code> is then applied for each item + * in the new collection. All items are collected into a set and items that are already + * in that set will not be perused again. The set becomes the result of the traversal. + */ +public final class Traverse extends CollectionFilter { + + private static final int maxParallelThreads = 2; + + public static final String OPERATOR = "traverse"; //$NON-NLS-1$ + + static class TraverseRequest { + Object parent; + VariableScope scope; + } + + final LinkedList queue = new LinkedList(); + int waitCount = 0; + + private class Worker extends Thread { + private final Map collector; + private final ExpressionContext context; + + Worker(Map collector, ExpressionContext context) { + this.collector = collector; + this.context = context; + } + + public void run() { + while (!interrupted()) { + TraverseRequest request; + synchronized (queue) { + while (queue.isEmpty()) { + try { + if (++waitCount == maxParallelThreads) { + // The queue is empty and everyone else is waiting so we're done! + queue.notifyAll(); + return; + } + queue.wait(); + --waitCount; + } catch (InterruptedException e) { + queue.clear(); + queue.notifyAll(); + return; + } + } + request = (TraverseRequest) queue.removeFirst(); + if (collector.put(request.parent, Boolean.TRUE) != null) + continue; + } + + VariableScope scope = new VariableScope(request.scope); + variable.setValue(scope, request.parent); + Iterator subIterator = lambda.evaluateAsIterator(context, scope); + while (subIterator.hasNext()) { + TraverseRequest subRequest = new TraverseRequest(); + subRequest.parent = subIterator.next(); + subRequest.scope = scope; + synchronized (queue) { + queue.addLast(subRequest); + queue.notifyAll(); + } + } + } + } + } + + public Traverse(Expression collection, LambdaExpression lambda) { + super(collection, lambda); + } + + Object evaluate(ExpressionContext context, VariableScope scope, Iterator iterator) { + Map collector = new IdentityHashMap(); + Worker[] workers = new Worker[maxParallelThreads]; + for (int idx = 0; idx < maxParallelThreads; ++idx) + workers[idx] = new Worker(collector, context); + while (iterator.hasNext()) { + TraverseRequest subRequest = new TraverseRequest(); + subRequest.parent = iterator.next(); + subRequest.scope = scope; + queue.addLast(subRequest); + } + for (int idx = 0; idx < maxParallelThreads; ++idx) + workers[idx].start(); + try { + for (int idx = 0; idx < maxParallelThreads; ++idx) + workers[idx].join(); + } catch (InterruptedException e) { + return null; + } + return collector.keySet(); + } + + String getOperator() { + return OPERATOR; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Unary.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Unary.java new file mode 100644 index 000000000..6e4ce3398 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Unary.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +/** + * The abstract base class for all unary expressions + */ +abstract class Unary extends Expression { + final Expression operand; + + Unary(Expression operand) { + this.operand = operand; + } + + public boolean accept(Visitor visitor) { + return super.accept(visitor) && operand.accept(visitor); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + return operand.evaluate(context, scope); + } + + public void toString(StringBuffer bld) { + bld.append(getOperator()); + appendOperand(bld, operand, getPriority()); + } + + int countReferenceToEverything() { + return operand.countReferenceToEverything(); + } + + abstract String getOperator(); +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/UnaryCollectionFilter.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/UnaryCollectionFilter.java new file mode 100644 index 000000000..11c00c513 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/UnaryCollectionFilter.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +abstract class UnaryCollectionFilter extends Unary { + + UnaryCollectionFilter(Expression collection) { + super(collection); + } + + public void toString(StringBuffer bld) { + if (operand instanceof Select) { + Select select = (Select) operand; + CollectionFilter.appendProlog(bld, select.operand, getOperator()); + appendOperand(bld, select.lambda, getPriority()); + } else + CollectionFilter.appendProlog(bld, operand, getOperator()); + bld.append(')'); + } + + int getPriority() { + return ExpressionParser.PRIORITY_COLLECTION; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Unique.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Unique.java new file mode 100644 index 000000000..241dd649d --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Unique.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.*; + +/** + * An expression that ensures that the elements of its collection is only returned + * once throughout the whole query. + */ +public final class Unique extends Binary { + public static class UniqueIterator extends MatchIteratorFilter { + private final Set uniqueSet; + + public UniqueIterator(Class instanceClass, Iterator iterator, Set uniqueSet) { + super(instanceClass, iterator); + this.uniqueSet = uniqueSet; + } + + protected boolean isMatch(Object val) { + synchronized (uniqueSet) { + return uniqueSet.add(val); + } + } + } + + static final String OPERATOR = "unique"; //$NON-NLS-1$ + + public Unique(Expression collection, Expression cacheId) { + super(collection, cacheId); + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + Object explicitCache = rhs.evaluate(context, scope); + Set uniqueSet; + if (explicitCache == null) + // No cache, we just ensure that the iteration is unique + uniqueSet = new HashSet(); + else { + if (!(explicitCache instanceof Set)) + throw new IllegalArgumentException("Unique cache must be a java.util.Set"); //$NON-NLS-1$ + uniqueSet = (Set) explicitCache; + } + return new UniqueIterator(Object.class, lhs.evaluateAsIterator(context, scope), uniqueSet); + } + + public void toString(StringBuffer bld) { + CollectionFilter.appendProlog(bld, lhs, getOperator()); + if (rhs != Constant.NULL_CONSTANT) + appendOperand(bld, rhs, ExpressionParser.PRIORITY_COMMA); + bld.append(')'); + } + + String getOperator() { + return OPERATOR; + } + + int getPriority() { + return ExpressionParser.PRIORITY_COLLECTION; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Variable.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Variable.java new file mode 100644 index 000000000..822b62d77 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Variable.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; + +/** + * An expression representing a variable stack in the current thread. + */ +public class Variable extends Expression { + + static final String KEYWORD_EVERYTHING = "everything"; //$NON-NLS-1$ + + static final String KEYWORD_ITEM = "item"; //$NON-NLS-1$ + + public static final Variable EVERYTHING = new Variable(KEYWORD_EVERYTHING); + + public static final Variable ITEM = new ItemVariable(KEYWORD_ITEM); + + private final String name; + + public static Variable createEach(String name) { + return new EachVariable(name); + } + + public static Variable create(String name) { + if (EachVariable.KEYWORD_EACH.equals(name)) + return new EachVariable(name); + if (KEYWORD_ITEM.equals(name)) + return ITEM; + if (KEYWORD_EVERYTHING.equals(name)) + return EVERYTHING; + return new Variable(name); + } + + Variable(String name) { + this.name = name; + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + return scope.getValue(this); + } + + public Iterator evaluateAsIterator(ExpressionContext context, VariableScope scope) { + Object value = evaluate(context, scope); + if (value instanceof IRepeatableIterator) + return ((IRepeatableIterator) value).getCopy(); + + Iterator itor = RepeatableIterator.create(value); + setValue(scope, itor); + return itor; + } + + public String getName() { + return name; + } + + public void toString(StringBuffer bld) { + bld.append(name); + } + + int countReferenceToEverything() { + return KEYWORD_EVERYTHING.equals(name) ? 1 : 0; + } + + int getPriority() { + return ExpressionParser.PRIORITY_VARIABLE; + } + + void setValue(VariableScope scope, Object value) { + scope.setValue(this, value); + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/VariableScope.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/VariableScope.java new file mode 100644 index 000000000..40f4652b4 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/VariableScope.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.IdentityHashMap; + +public final class VariableScope { + public static final VariableScope DUMMY = new VariableScope(); + + private final VariableScope parentScope; + + private IdentityHashMap values; + + private EachVariable eachVariable; + private Object each; + private Object item; + + public VariableScope() { + parentScope = null; + } + + VariableScope(VariableScope parentScope) { + this.parentScope = parentScope; + this.each = parentScope.each; + this.eachVariable = parentScope.eachVariable; + this.item = parentScope.item; + } + + synchronized Object getValue(Variable variable) { + Object value = null; + if (values == null) + return parentScope == null ? null : parentScope.getValue(variable); + + value = values.get(variable); + if (value == null && parentScope != null && !values.containsKey(variable)) + value = parentScope.getValue(variable); + return value; + } + + synchronized void setValue(Variable variable, Object value) { + if (values == null) + values = new IdentityHashMap(5); + values.put(variable, value); + } + + Object getItem() { + return item; + } + + void setItem(Object value) { + item = value; + } + + Object getEach(EachVariable eachVar) { + Object value = each; + if (eachVar != eachVariable) { + value = null; + if (parentScope != null) + value = parentScope.getEach(eachVar); + } + return value; + } + + void setEach(EachVariable eachVar, Object value) { + eachVariable = eachVar; + each = value; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/VersionConstructor.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/VersionConstructor.java new file mode 100644 index 000000000..67565f56c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/VersionConstructor.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import org.eclipse.equinox.internal.provisional.p2.metadata.Version; + +public class VersionConstructor extends Constructor { + + static final String KEYWORD = "version"; //$NON-NLS-1$ + + public VersionConstructor(Expression[] operands) { + super(operands); + } + + Object createInstance(String arg) { + return Version.create(arg); + } + + String getOperator() { + return KEYWORD; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/WrappedIQuery.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/WrappedIQuery.java new file mode 100644 index 000000000..0c8ff756c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/WrappedIQuery.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.ql; + +import java.util.Iterator; +import org.eclipse.equinox.internal.provisional.p2.metadata.query.Collector; +import org.eclipse.equinox.internal.provisional.p2.metadata.query.IMatchQuery; +import org.eclipse.equinox.p2.metadata.query.IQuery; + +public final class WrappedIQuery extends Constructor { + + static final String KEYWORD = "iquery"; //$NON-NLS-1$ + + public WrappedIQuery(Expression[] operands) { + super(operands); + int argCount = operands.length; + if (argCount < 1) + throw new IllegalArgumentException("iquery must have at least one argument"); //$NON-NLS-1$ + if (argCount > 3) + throw new IllegalArgumentException("iquery must have max 3 arguments"); //$NON-NLS-1$ + } + + public Object evaluate(ExpressionContext context, VariableScope scope) { + Object query = operands[0].evaluate(context, scope); + + if (query instanceof IMatchQuery) { + if (operands.length > 2) + throw new IllegalArgumentException("iquery third argument cannot be combined with a match query"); //$NON-NLS-1$ + + Object value = null; + if (operands.length > 1) + value = operands[1].evaluate(context, scope); + else + value = Variable.ITEM.evaluate(context, scope); + return Boolean.valueOf(((IMatchQuery) query).isMatch(value)); + } + + if (!(query instanceof IQuery)) + throw new IllegalArgumentException("iquery first argument must be an IQuery instance"); //$NON-NLS-1$ + + Collector collector; + if (operands.length < 3) + collector = new Collector(); + else { + Object cobj = operands[2].evaluate(context, scope); + if (cobj instanceof Collector) + collector = (Collector) cobj; + else if (cobj == null) + collector = new Collector(); + else + throw new IllegalArgumentException("iquery third argument must be a collector"); //$NON-NLS-1$ + } + + Iterator iterator = null; + if (operands.length > 1) + iterator = operands[1].evaluateAsIterator(context, scope); + else + iterator = Variable.EVERYTHING.evaluateAsIterator(context, scope); + return ((IQuery) query).perform(iterator, collector); + } + + String getOperator() { + return KEYWORD; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/ExpressionQuery.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/ExpressionQuery.java new file mode 100644 index 000000000..6485f9cb6 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/ExpressionQuery.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.p2.ql; + +import java.util.Iterator; +import java.util.Map; +import org.eclipse.equinox.internal.p2.ql.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.IVersionedId; +import org.eclipse.equinox.internal.provisional.p2.metadata.query.Collector; +import org.eclipse.equinox.internal.provisional.p2.metadata.query.ContextQuery; +import org.eclipse.equinox.p2.metadata.IArtifactKey; +import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; +import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; + +/** + * An IQuery implementation that is based on the p2 query language. + */ +public class ExpressionQuery extends ContextQuery { + private static final ExpressionParser parser = new ExpressionParser(); + private static final Object[] noParameters = new Object[0]; + + private final Class instanceClass; + private final ContextExpression expression; + private final Object[] parameters; + + public ExpressionQuery(Class instanceClass, ContextExpression expression, Object[] parameters) { + this.expression = expression; + this.parameters = parameters == null ? noParameters : parameters; + this.instanceClass = instanceClass; + } + + public ExpressionQuery(Class instanceClass, String expression) { + this(instanceClass, parser.parseQuery(expression), null); + } + + public ExpressionQuery(Class instanceClass, String expression, Object param1) { + this(instanceClass, parser.parseQuery(expression), new Object[] {param1}); + } + + public ExpressionQuery(Class instanceClass, String expression, Object param1, Object param2) { + this(instanceClass, parser.parseQuery(expression), new Object[] {param1, param2}); + } + + public ExpressionQuery(Class instanceClass, String expression, Object param1, Object param2, Object param3) { + this(instanceClass, parser.parseQuery(expression), new Object[] {param1, param2, param3}); + } + + public ExpressionQuery(ContextExpression expression, Map args) { + this(IVersionedId.class, expression, new Object[] {args}); + } + + public ExpressionQuery(ContextExpression expr, Object[] objects) { + this(IVersionedId.class, expr, objects); + } + + public ExpressionQuery(String expression) { + this(IVersionedId.class, parser.parseQuery(expression), noParameters); + } + + public ExpressionQuery(String expression, Object param1) { + this(IVersionedId.class, parser.parseQuery(expression), new Object[] {param1}); + } + + public ExpressionQuery(String expression, Object param1, Object param2) { + this(IVersionedId.class, parser.parseQuery(expression), new Object[] {param1, param2}); + } + + public ExpressionQuery(String expression, Object param1, Object param2, Object param3) { + this(IVersionedId.class, parser.parseQuery(expression), new Object[] {param1, param2, param3}); + } + + public Class getInstanceClass() { + return instanceClass; + } + + public Object getProperty(String key) { + if (IArtifactRepository.QUERY_EXCLUDE_KEYS.equals(key)) + return Boolean.valueOf(!instanceClass.isAssignableFrom(IArtifactKey.class)); + + if (IArtifactRepository.QUERY_EXCLUDE_DESCRIPTORS.equals(key)) + return Boolean.valueOf(!instanceClass.isAssignableFrom(IArtifactDescriptor.class)); + + return super.getProperty(key); + } + + public Collector perform(Iterator iterator, Collector collector) { + iterator = expression.evaluateAsIterator(new ExpressionContext(instanceClass, parameters, iterator, expression.needsRepeatedIterations()), new VariableScope()); + while (iterator.hasNext()) { + Object nxt = iterator.next(); + if (!collector.accept(nxt)) + break; + } + return collector; + } +} diff --git a/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/PredicateQuery.java b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/PredicateQuery.java new file mode 100644 index 000000000..9f57ccdf6 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/PredicateQuery.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.p2.ql; + +import java.util.Map; +import org.eclipse.equinox.internal.p2.ql.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.IVersionedId; +import org.eclipse.equinox.internal.provisional.p2.metadata.query.MatchQuery; +import org.eclipse.equinox.p2.metadata.IArtifactKey; +import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; +import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; + +/** + * An IQuery implementation that is based on the p2 query language. + */ +public class PredicateQuery extends MatchQuery { + private static final ExpressionParser parser = new ExpressionParser(); + + private final ExpressionContext context; + private final VariableScope scope; + private final ItemExpression expression; + + public PredicateQuery(Class instanceClass, ItemExpression expression, Object[] parameters) { + this.expression = expression; + this.context = new ExpressionContext(instanceClass, parameters, null); + this.scope = new VariableScope(); + } + + public PredicateQuery(Class instanceClass, String expression) { + this(instanceClass, parser.parsePredicate(expression), null); + } + + public PredicateQuery(Class instanceClass, String expression, Object param1) { + this(instanceClass, parser.parsePredicate(expression), new Object[] {param1}); + } + + public PredicateQuery(Class instanceClass, String expression, Object param1, Object param2) { + this(instanceClass, parser.parsePredicate(expression), new Object[] {param1, param2}); + } + + public PredicateQuery(Class instanceClass, String expression, Object param1, Object param2, Object param3) { + this(instanceClass, parser.parsePredicate(expression), new Object[] {param1, param2, param3}); + } + + public PredicateQuery(ItemExpression expression, Map args) { + this(IVersionedId.class, expression, new Object[] {args}); + } + + public PredicateQuery(ItemExpression expr, Object[] objects) { + this(IVersionedId.class, expr, objects); + } + + public PredicateQuery(String expression) { + this(IVersionedId.class, parser.parsePredicate(expression), null); + } + + public PredicateQuery(String expression, Object param1) { + this(IVersionedId.class, parser.parsePredicate(expression), new Object[] {param1}); + } + + public PredicateQuery(String expression, Object param1, Object param2) { + this(IVersionedId.class, parser.parsePredicate(expression), new Object[] {param1, param2}); + } + + public PredicateQuery(String expression, Object param1, Object param2, Object param3) { + this(IVersionedId.class, parser.parsePredicate(expression), new Object[] {param1, param2, param3}); + } + + public Object getProperty(String key) { + if (IArtifactRepository.QUERY_EXCLUDE_KEYS.equals(key)) + return Boolean.valueOf(!context.getInstanceClass().isAssignableFrom(IArtifactKey.class)); + + if (IArtifactRepository.QUERY_EXCLUDE_DESCRIPTORS.equals(key)) + return Boolean.valueOf(!context.getInstanceClass().isAssignableFrom(IArtifactDescriptor.class)); + + return super.getProperty(key); + } + + public boolean isMatch(Object candidate) { + return expression.isMatch(context, scope, candidate); + } +} |