Merge pull request #19012 from jdconrad/init2

Painless Initializers
This commit is contained in:
Jack Conradson 2016-06-21 13:08:53 -07:00 committed by GitHub
commit ea206237e3
10 changed files with 1588 additions and 602 deletions

View File

@ -133,6 +133,8 @@ unary[boolean c] returns [boolean s = true]
| { !$c }? TRUE { $s = false; } # true
| { !$c }? FALSE { $s = false; } # false
| { !$c }? NULL { $s = false; } # null
| { !$c }? listinitializer { $s = false; } # listinit
| { !$c }? mapinitializer { $s = false; } # mapinit
| { !$c }? ( BOOLNOT | BWNOT | ADD | SUB ) unary[false] # operator
| LP decltype RP unary[$c] # cast
;
@ -140,7 +142,7 @@ unary[boolean c] returns [boolean s = true]
chain[boolean c]
: p = primary[$c] secondary[$p.s]* # dynamic
| decltype dot secondary[true]* # static
| NEW TYPE (LBRACE expression RBRACE)+ (dot secondary[true]*)? # newarray
| arrayinitializer # newarray
;
primary[boolean c] returns [boolean s = true]
@ -213,3 +215,22 @@ capturingFuncref
localFuncref
: THIS REF ID
;
arrayinitializer
: NEW TYPE (LBRACE expression RBRACE)+ (dot secondary[true]*)? # newstandardarray
| NEW TYPE LBRACE RBRACE LBRACK ( expression ( COMMA expression )* )? SEMICOLON? RBRACK # newinitializedarray
;
listinitializer
: LBRACE expression ( COMMA expression)* RBRACE
| LBRACE RBRACE
;
mapinitializer
: LBRACE maptoken ( COMMA maptoken )* RBRACE
| LBRACE COLON RBRACE
;
maptoken
: expression COLON expression
;

View File

@ -277,6 +277,20 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNull(PainlessParser.NullContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitListinit(PainlessParser.ListinitContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitMapinit(PainlessParser.MapinitContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
@ -452,4 +466,39 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitLocalFuncref(PainlessParser.LocalFuncrefContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNewstandardarray(PainlessParser.NewstandardarrayContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNewinitializedarray(PainlessParser.NewinitializedarrayContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitListinitializer(PainlessParser.ListinitializerContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitMapinitializer(PainlessParser.MapinitializerContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitMaptoken(PainlessParser.MaptokenContext ctx) { return visitChildren(ctx); }
}

View File

@ -263,6 +263,20 @@ interface PainlessParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitNull(PainlessParser.NullContext ctx);
/**
* Visit a parse tree produced by the {@code listinit}
* labeled alternative in {@link PainlessParser#unary}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitListinit(PainlessParser.ListinitContext ctx);
/**
* Visit a parse tree produced by the {@code mapinit}
* labeled alternative in {@link PainlessParser#unary}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitMapinit(PainlessParser.MapinitContext ctx);
/**
* Visit a parse tree produced by the {@code operator}
* labeled alternative in {@link PainlessParser#unary}.
@ -428,4 +442,36 @@ interface PainlessParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitLocalFuncref(PainlessParser.LocalFuncrefContext ctx);
/**
* Visit a parse tree produced by the {@code newstandardarray}
* labeled alternative in {@link PainlessParser#arrayinitializer}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNewstandardarray(PainlessParser.NewstandardarrayContext ctx);
/**
* Visit a parse tree produced by the {@code newinitializedarray}
* labeled alternative in {@link PainlessParser#arrayinitializer}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNewinitializedarray(PainlessParser.NewinitializedarrayContext ctx);
/**
* Visit a parse tree produced by {@link PainlessParser#listinitializer}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitListinitializer(PainlessParser.ListinitializerContext ctx);
/**
* Visit a parse tree produced by {@link PainlessParser#mapinitializer}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitMapinitializer(PainlessParser.MapinitializerContext ctx);
/**
* Visit a parse tree produced by {@link PainlessParser#maptoken}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitMaptoken(PainlessParser.MaptokenContext ctx);
}

View File

@ -30,6 +30,15 @@ import org.antlr.v4.runtime.atn.PredictionMode;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.antlr.PainlessParser.ListinitContext;
import org.elasticsearch.painless.antlr.PainlessParser.ListinitializerContext;
import org.elasticsearch.painless.antlr.PainlessParser.MapinitContext;
import org.elasticsearch.painless.antlr.PainlessParser.MapinitializerContext;
import org.elasticsearch.painless.antlr.PainlessParser.MaptokenContext;
import org.elasticsearch.painless.antlr.PainlessParser.NewinitializedarrayContext;
import org.elasticsearch.painless.antlr.PainlessParser.NewstandardarrayContext;
import org.elasticsearch.painless.node.EListInit;
import org.elasticsearch.painless.node.EMapInit;
import org.elasticsearch.painless.node.SFunction.Reserved;
import org.elasticsearch.painless.node.SSource.MainMethodReserved;
import org.elasticsearch.painless.node.SFunction.FunctionReserved;
@ -720,6 +729,16 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
return new ENull(location(ctx));
}
@Override
public Object visitListinit(ListinitContext ctx) {
return visit(ctx.listinitializer());
}
@Override
public Object visitMapinit(MapinitContext ctx) {
return visit(ctx.mapinitializer());
}
@Override
public Object visitOperator(OperatorContext ctx) {
if (ctx.SUB() != null && ctx.unary() instanceof NumericContext) {
@ -797,27 +816,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
@Override
public Object visitNewarray(NewarrayContext ctx) {
String type = ctx.TYPE().getText();
List<AExpression> expressions = new ArrayList<>();
for (ExpressionContext expression : ctx.expression()) {
expressions.add((AExpression)visitExpression(expression));
}
List<ALink> links = new ArrayList<>();
links.add(new LNewArray(location(ctx), type, expressions));
if (ctx.dot() != null) {
links.add((ALink)visit(ctx.dot()));
for (SecondaryContext secondary : ctx.secondary()) {
links.add((ALink)visit(secondary));
}
} else if (!ctx.secondary().isEmpty()) {
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
}
return links;
return visit(ctx.arrayinitializer());
}
@Override
@ -1020,7 +1019,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
new EChain(location,
new LNewArray(location, arrayType, Arrays.asList(
new EChain(location,
new LVariable(location, "size"))))));
new LVariable(location, "size"))), false)));
String name = nextLambda();
globals.addSyntheticMethod(new SFunction(new FunctionReserved(), location, arrayType, name,
Arrays.asList("int"), Arrays.asList("size"), Arrays.asList(code), true));
@ -1039,6 +1038,75 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
return new EFunctionRef(location(ctx), ctx.THIS().getText(), ctx.ID().getText());
}
@Override
public Object visitNewstandardarray(NewstandardarrayContext ctx) {
String type = ctx.TYPE().getText();
List<AExpression> expressions = new ArrayList<>();
for (ExpressionContext expression : ctx.expression()) {
expressions.add((AExpression)visitExpression(expression));
}
List<ALink> links = new ArrayList<>();
links.add(new LNewArray(location(ctx), type, expressions, false));
if (ctx.dot() != null) {
links.add((ALink)visit(ctx.dot()));
for (SecondaryContext secondary : ctx.secondary()) {
links.add((ALink)visit(secondary));
}
} else if (!ctx.secondary().isEmpty()) {
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
}
return links;
}
@Override
public Object visitNewinitializedarray(NewinitializedarrayContext ctx) {
String type = ctx.TYPE().getText();
List<AExpression> expressions = new ArrayList<>();
for (ExpressionContext expression : ctx.expression()) {
expressions.add((AExpression)visitExpression(expression));
}
List<ALink> links = new ArrayList<>();
links.add(new LNewArray(location(ctx), type, expressions, true));
return links;
}
@Override
public Object visitListinitializer(ListinitializerContext ctx) {
List<AExpression> values = new ArrayList<>();
for (ExpressionContext expression : ctx.expression()) {
values.add((AExpression)visitExpression(expression));
}
return new EListInit(location(ctx), values);
}
@Override
public Object visitMapinitializer(MapinitializerContext ctx) {
List<AExpression> keys = new ArrayList<>();
List<AExpression> values = new ArrayList<>();
for (MaptokenContext maptoken : ctx.maptoken()) {
keys.add((AExpression)visitExpression(maptoken.expression(0)));
values.add((AExpression)visitExpression(maptoken.expression(1)));
}
return new EMapInit(location(ctx), keys, values);
}
@Override
public Object visitMaptoken(MaptokenContext ctx) {
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
}
/** Returns name of next lambda */
private String nextLambda() {
return "lambda$" + syntheticCounter++;

View File

@ -0,0 +1,100 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.MethodKey;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import java.util.List;
import java.util.Set;
/**
* Represents a list initialization shortcut.
*/
public class EListInit extends AExpression {
final List<AExpression> values;
Method constructor = null;
Method method = null;
public EListInit(Location location, List<AExpression> values) {
super(location);
this.values = values;
}
@Override
void extractVariables(Set<String> variables) {
for (AExpression value : values) {
value.extractVariables(variables);
}
}
@Override
void analyze(Locals locals) {
try {
actual = Definition.getType("ArrayList");
} catch (IllegalArgumentException exception) {
throw createError(new IllegalStateException("Illegal tree structure."));
}
constructor = actual.struct.constructors.get(new MethodKey("<init>", 0));
if (constructor == null) {
throw createError(new IllegalStateException("Illegal tree structure."));
}
method = actual.struct.methods.get(new MethodKey("add", 1));
if (method == null) {
throw createError(new IllegalStateException("Illegal tree structure."));
}
for (int index = 0; index < values.size(); ++index) {
AExpression expression = values.get(index);
expression.expected = Definition.DEF_TYPE;
expression.internal = true;
expression.analyze(locals);
values.set(index, expression.cast(locals));
}
}
@Override
void write(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location);
writer.newInstance(actual.type);
writer.dup();
writer.invokeConstructor(constructor.owner.type, constructor.method);
for (AExpression value : values) {
writer.dup();
value.write(writer, globals);
method.write(writer);
writer.pop();
}
}
}

View File

@ -0,0 +1,123 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.MethodKey;
import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import java.util.List;
import java.util.Set;
/**
* Represents a map initialization shortcut.
*/
public class EMapInit extends AExpression {
final List<AExpression> keys;
final List<AExpression> values;
Method constructor = null;
Method method = null;
public EMapInit(Location location, List<AExpression> keys, List<AExpression> values) {
super(location);
this.keys = keys;
this.values = values;
}
@Override
void extractVariables(Set<String> variables) {
for (AExpression key : keys) {
key.extractVariables(variables);
}
for (AExpression value : values) {
value.extractVariables(variables);
}
}
@Override
void analyze(Locals locals) {
try {
actual = Definition.getType("HashMap");
} catch (IllegalArgumentException exception) {
throw createError(new IllegalStateException("Illegal tree structure."));
}
constructor = actual.struct.constructors.get(new MethodKey("<init>", 0));
if (constructor == null) {
throw createError(new IllegalStateException("Illegal tree structure."));
}
method = actual.struct.methods.get(new MethodKey("put", 2));
if (method == null) {
throw createError(new IllegalStateException("Illegal tree structure."));
}
if (keys.size() != values.size()) {
throw createError(new IllegalStateException("Illegal tree structure."));
}
for (int index = 0; index < keys.size(); ++index) {
AExpression expression = keys.get(index);
expression.expected = Definition.DEF_TYPE;
expression.internal = true;
expression.analyze(locals);
keys.set(index, expression.cast(locals));
}
for (int index = 0; index < values.size(); ++index) {
AExpression expression = values.get(index);
expression.expected = Definition.DEF_TYPE;
expression.internal = true;
expression.analyze(locals);
values.set(index, expression.cast(locals));
}
}
@Override
void write(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location);
writer.newInstance(actual.type);
writer.dup();
writer.invokeConstructor(constructor.owner.type, constructor.method);
for (int index = 0; index < keys.size(); ++index) {
AExpression key = keys.get(index);
AExpression value = values.get(index);
writer.dup();
key.write(writer, globals);
value.write(writer, globals);
method.write(writer);
writer.pop();
}
}
}

View File

@ -37,12 +37,14 @@ public final class LNewArray extends ALink {
final String type;
final List<AExpression> arguments;
final boolean initialize;
public LNewArray(Location location, String type, List<AExpression> arguments) {
public LNewArray(Location location, String type, List<AExpression> arguments, boolean initialize) {
super(location, -1);
this.type = Objects.requireNonNull(type);
this.arguments = Objects.requireNonNull(arguments);
this.initialize = initialize;
}
@Override
@ -73,12 +75,13 @@ public final class LNewArray extends ALink {
for (int argument = 0; argument < arguments.size(); ++argument) {
AExpression expression = arguments.get(argument);
expression.expected = Definition.INT_TYPE;
expression.expected = initialize ? Definition.getType(type.struct, 0) : Definition.INT_TYPE;
expression.internal = true;
expression.analyze(locals);
arguments.set(argument, expression.cast(locals));
}
after = Definition.getType(type.struct, arguments.size());
after = Definition.getType(type.struct, initialize ? 1 : arguments.size());
return this;
}
@ -92,6 +95,19 @@ public final class LNewArray extends ALink {
void load(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location);
if (initialize) {
writer.push(arguments.size());
writer.newArray(Definition.getType(after.struct, 0).type);
for (int index = 0; index < arguments.size(); ++index) {
AExpression argument = arguments.get(index);
writer.dup();
writer.push(index);
argument.write(writer, globals);
writer.arrayStore(Definition.getType(after.struct, 0).type);
}
} else {
for (AExpression argument : arguments) {
argument.write(writer, globals);
}
@ -102,6 +118,7 @@ public final class LNewArray extends ALink {
writer.newArray(Definition.getType(after.struct, 0).type);
}
}
}
@Override
void store(MethodWriter writer, Globals globals) {

View File

@ -44,6 +44,8 @@
* {@link org.elasticsearch.painless.node.EDecimal} - Represents a decimal constant.
* {@link org.elasticsearch.painless.node.EExplicit} - Represents an explicit cast.
* {@link org.elasticsearch.painless.node.EFunctionRef} - Represents a function reference (non-capturing).
* {@link org.elasticsearch.painless.node.EListInit} - Represents a list initialization shortcut.
* {@link org.elasticsearch.painless.node.EMapInit} - Represents a map initializiation shortcut.
* {@link org.elasticsearch.painless.node.ENull} - Represents a null constant.
* {@link org.elasticsearch.painless.node.ENumeric} - Represents a non-decimal numeric constant.
* {@link org.elasticsearch.painless.node.EUnary} - Represents a unary math expression.

View File

@ -0,0 +1,146 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.painless;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class InitializerTests extends ScriptTestCase {
@SuppressWarnings({"unchecked", "rawtypes"})
public void testArrayInitializers() {
int[] ints = (int[])exec("new int[] {}");
assertEquals(0, ints.length);
ints = (int[])exec("new int[] {5, 7, -1, 14}");
assertEquals(4, ints.length);
assertEquals(5, ints[0]);
assertEquals(7, ints[1]);
assertEquals(-1, ints[2]);
assertEquals(14, ints[3]);
ints = (int[])exec("int y = 2; int z = 3; int[] x = new int[] {y*z, y + z, y - z, y, z}; return x;");
assertEquals(5, ints.length);
assertEquals(6, ints[0]);
assertEquals(5, ints[1]);
assertEquals(-1, ints[2]);
assertEquals(2, ints[3]);
assertEquals(3, ints[4]);
Object[] objects = (Object[])exec("int y = 2; List z = new ArrayList(); String s = 'aaa';" +
"Object[] x = new Object[] {y, z, 1 + s, s + 'aaa'}; return x;");
assertEquals(4, objects.length);
assertEquals(new Integer(2), objects[0]);
assertEquals(new ArrayList(), objects[1]);
assertEquals("1aaa", objects[2]);
assertEquals("aaaaaa", objects[3]);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public void testListInitializers() {
List list = (List)exec("[]");
assertEquals(0, list.size());
list = (List)exec("[5, 7, -1, 14]");
assertEquals(4, list.size());
assertEquals(5, list.get(0));
assertEquals(7, list.get(1));
assertEquals(-1, list.get(2));
assertEquals(14, list.get(3));
list = (List)exec("int y = 2; int z = 3; def x = [y*z, y + z, y - z, y, z]; return x;");
assertEquals(5, list.size());
assertEquals(6, list.get(0));
assertEquals(5, list.get(1));
assertEquals(-1, list.get(2));
assertEquals(2, list.get(3));
assertEquals(3, list.get(4));
list = (List)exec("int y = 2; List z = new ArrayList(); String s = 'aaa'; List x = [y, z, 1 + s, s + 'aaa']; return x;");
assertEquals(4, list.size());
assertEquals(new Integer(2), list.get(0));
assertEquals(new ArrayList(), list.get(1));
assertEquals("1aaa", list.get(2));
assertEquals("aaaaaa", list.get(3));
}
@SuppressWarnings({"unchecked", "rawtypes"})
public void testMapInitializers() {
Map map = (Map)exec("[:]");
assertEquals(0, map.size());
map = (Map)exec("[5 : 7, -1 : 14]");
assertEquals(2, map.size());
assertEquals(new Integer(7), map.get(5));
assertEquals(new Integer(14), map.get(-1));
map = (Map)exec("int y = 2; int z = 3; Map x = [y*z : y + z, y - z : y, z : z]; return x;");
assertEquals(3, map.size());
assertEquals(new Integer(5), map.get(6));
assertEquals(new Integer(2), map.get(-1));
assertEquals(new Integer(3), map.get(3));
map = (Map)exec("int y = 2; List z = new ArrayList(); String s = 'aaa';" +
"def x = [y : z, 1 + s : s + 'aaa']; return x;");
assertEquals(2, map.size());
assertEquals(new ArrayList(), map.get(2));
assertEquals("aaaaaa", map.get("1aaa"));
}
@SuppressWarnings({"unchecked", "rawtypes"})
public void testCrazyInitializer() {
Map map = (Map)exec("int y = 2; int z = 3; Map x = [y*z : y + z, 's' : [y, [y : [[z], [], [:]]]], z : [z, 9]]; return x;");
List list0 = new ArrayList();
list0.add(3);
List list1 = new ArrayList();
list1.add(list0);
list1.add(new ArrayList());
list1.add(new HashMap());
Map map0 = new HashMap();
map0.put(2, list1);
List list2 = new ArrayList();
list2.add(2);
list2.add(map0);
List list3 = new ArrayList();
list3.add(3);
list3.add(9);
assertEquals(3, map.size());
assertEquals(new Integer(5), map.get(6));
assertEquals(list2, map.get("s"));
assertEquals(list3, map.get(3));
}
}