Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrik Lindberg2009-12-01 17:41:31 +0000
committerHenrik Lindberg2009-12-01 17:41:31 +0000
commit131f9832b57dd8f3c845d4b18d46af42c35d6fbc (patch)
tree90c37197e9faaa521b24b93a216c179931214e7b /bundles/org.eclipse.equinox.p2.ql
parentd8f0c6b513a4449d5bbd87d7ddc193aebb1cebfb (diff)
downloadrt.equinox.p2-131f9832b57dd8f3c845d4b18d46af42c35d6fbc.tar.gz
rt.equinox.p2-131f9832b57dd8f3c845d4b18d46af42c35d6fbc.tar.xz
rt.equinox.p2-131f9832b57dd8f3c845d4b18d46af42c35d6fbc.zip
[294691] Checkin of o.e.e.p2.ql bundle
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.ql')
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/.classpath7
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/.project34
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/.settings/org.eclipse.core.resources.prefs3
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/.settings/org.eclipse.jdt.core.prefs345
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/.settings/org.eclipse.jdt.ui.prefs57
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/META-INF/MANIFEST.MF22
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/about.html28
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/build.properties15
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/model/p2ql.bnf67
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/plugin.properties8
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/All.java38
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/And.java70
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Array.java51
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ArrayIterator.java49
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/At.java73
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Binary.java47
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ClassConstructor.java32
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Collect.java33
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/CollectIterator.java49
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/CollectionFilter.java63
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Compare.java65
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Condition.java46
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Constant.java69
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Constructor.java55
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ContextExpression.java45
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/EachVariable.java34
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Equals.java54
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Exists.java38
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Expression.java124
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ExpressionContext.java79
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ExpressionFilter.java35
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ExpressionParser.java867
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/FilterConstructor.java34
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/First.java39
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Flatten.java31
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/FlattenIterator.java63
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/IRepeatableIterator.java25
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/IndexedParameter.java31
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ItemExpression.java47
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/ItemVariable.java33
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/KeyedParameter.java31
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LambdaExpression.java110
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Latest.java91
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Limit.java83
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LocalizedKeys.java73
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LocalizedMap.java134
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/LocalizedProperty.java43
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/MatchIteratorFilter.java65
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Matches.java117
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Member.java117
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/NAry.java58
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Not.java34
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Or.java67
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Parameter.java22
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/QLActivator.java30
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/QueryParseException.java19
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/RangeConstructor.java30
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Reject.java38
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/RepeatableIterator.java236
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Select.java38
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/SetConstructor.java33
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/SimplePattern.java124
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Traverse.java114
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Unary.java41
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/UnaryCollectionFilter.java32
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Unique.java70
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/Variable.java81
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/VariableScope.java76
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/VersionConstructor.java30
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/internal/p2/ql/WrappedIQuery.java73
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/ExpressionQuery.java103
-rw-r--r--bundles/org.eclipse.equinox.p2.ql/src/org/eclipse/equinox/p2/ql/PredicateQuery.java90
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 (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). 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, &quot;Program&quot; 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 (&quot;Redistributor&quot;) 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.&lt;operation&gt;(y | &lt;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(&lt;expr&gt;) or version(&lt;expr&gt;)
+ */
+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 &quot;matching&quot; 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>&lt;any&gt;</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 &quot;value&quot; 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);
+ }
+}

Back to the top