本文整理汇总了C#中ProtoCore.AST.AssociativeAST.AssociativeNode类的典型用法代码示例。如果您正苦于以下问题:C# AssociativeNode类的具体用法?C# AssociativeNode怎么用?C# AssociativeNode使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。
AssociativeNode类属于ProtoCore.AST.AssociativeAST命名空间,在下文中一共展示了AssociativeNode类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: CreateOutputAST
protected AssociativeNode CreateOutputAST(
AssociativeNode codeInputNode, List<AssociativeNode> inputAstNodes,
List<Tuple<string, AssociativeNode>> additionalBindings)
{
var names =
additionalBindings.Select(
x => AstFactory.BuildStringNode(x.Item1) as AssociativeNode).ToList();
names.Add(AstFactory.BuildStringNode("IN"));
var vals = additionalBindings.Select(x => x.Item2).ToList();
vals.Add(AstFactory.BuildExprList(inputAstNodes));
Func<string, IList, IList, object> backendMethod =
IronPythonEvaluator.EvaluateIronPythonScript;
return AstFactory.BuildAssignment(
GetAstIdentifierForOutputIndex(0),
AstFactory.BuildFunctionCall(
backendMethod,
new List<AssociativeNode>
{
codeInputNode,
AstFactory.BuildExprList(names),
AstFactory.BuildExprList(vals)
}));
}
示例2: CreateAssignmentNode
private static BinaryExpressionNode CreateAssignmentNode(AssociativeNode rhsNode)
{
IdentifierNode lhs = new IdentifierNode(string.Format("tVar_{0}", staticVariableIndex++));
BinaryExpressionNode bNode = new BinaryExpressionNode(lhs, rhsNode, ProtoCore.DSASM.Operator.assign);
return bNode;
}
示例3: GenerateBridgeDataAst
public static AssociativeNode GenerateBridgeDataAst(string id, AssociativeNode input)
{
Action<string, object> bridgeData = BridgeData;
return AstFactory.BuildFunctionCall(
bridgeData,
new List<AssociativeNode> { AstFactory.BuildStringNode(id), input });
}
示例4: TypedParameter
private string summary = null; // Indicating that it is not initialized.
public TypedParameter(string parameter, ProtoCore.Type type, AssociativeNode defaultValue = null)
{
if (parameter == null)
throw new ArgumentNullException("parameter");
Name = parameter;
Type = type;
DefaultValue = defaultValue;
}
示例5: TopologicalSortVisit
private void TopologicalSortVisit(AssociativeNode n, List<AssociativeNode> visited, List<AssociativeNode> topologicalSort)
{
if (visited.Contains(n))
return;
visited.Add(n);
foreach (AssociativeNode node in tracker.DirectContingents[n])
TopologicalSortVisit(node, visited, topologicalSort);
topologicalSort.Add(n);
}
示例6: AddNode
public void AddNode(AssociativeNode node)
{
if (AllNodes.Contains(node))
return;
AllNodes.Add(node);
if (!DirectContingents.ContainsKey(node))
DirectContingents.Add(node, new List<AssociativeNode>());
if (!DirectDependents.ContainsKey(node))
DirectDependents.Add(node, new List<AssociativeNode>());
}
示例7: AssignIdentifiersForFunctionCall
protected override void AssignIdentifiersForFunctionCall(
NodeModel model, AssociativeNode rhs, List<AssociativeNode> resultAst)
{
if (model.OutPortData.Count == 1)
{
resultAst.Add(AstFactory.BuildAssignment(model.AstIdentifierForPreview, rhs));
resultAst.Add(
AstFactory.BuildAssignment(
model.GetAstIdentifierForOutputIndex(0),
model.AstIdentifierForPreview));
}
else
base.AssignIdentifiersForFunctionCall(model, rhs, resultAst);
}
示例8: TypedParameter
/// <summary>
/// This function creates TypedParameter
/// </summary>
/// <param name="parameter">parameter name</param>
/// <param name="type">parameter type</param>
/// <param name="defaultValue">parameter default value</param>
/// <param name="shortArgumentName">short name is used as tooltip</param>
/// <param name="summary">parameter description</param>
public TypedParameter(string parameter, ProtoCore.Type type, AssociativeNode defaultValue = null, string shortArgumentName = null, string summary = null)
{
if (parameter == null)
throw new ArgumentNullException("parameter");
Name = parameter;
Type = type;
DefaultValue = defaultValue;
if (defaultValue != null)
defaultValueString = defaultValue.ToString();
else
defaultValueString = shortArgumentName;
this.summary = summary;
}
示例9: BuildAstForPartialMultiOutput
protected override void BuildAstForPartialMultiOutput(
NodeModel model, AssociativeNode rhs, List<AssociativeNode> resultAst)
{
base.BuildAstForPartialMultiOutput(model, rhs, resultAst);
var emptyList = AstFactory.BuildExprList(new List<AssociativeNode>());
var previewIdInit = AstFactory.BuildAssignment(model.AstIdentifierForPreview, emptyList);
resultAst.Add(previewIdInit);
resultAst.AddRange(
Definition.ReturnKeys.Select(
(rtnKey, idx) =>
AstFactory.BuildAssignment(
AstFactory.BuildIdentifier(
model.AstIdentifierForPreview.Name,
AstFactory.BuildStringNode(rtnKey)),
model.GetAstIdentifierForOutputIndex(idx))));
}
示例10: BuildAstForPartialMultiOutput
/// <summary>
/// Produces AST for a partial function application of a multi-output function.
/// </summary>
/// <param name="model">NodeModel to produce AST for.</param>
/// <param name="rhs">AST representing the partial application. This will need to be used to assign all output port identifiers.</param>
/// <param name="resultAst">Result accumulator: add all new output AST to this list.</param>
protected virtual void BuildAstForPartialMultiOutput(
NodeModel model, AssociativeNode rhs, List<AssociativeNode> resultAst)
{
var missingAmt =
Enumerable.Range(0, model.InPortData.Count).Count(x => !model.HasInput(x));
var tmp =
AstFactory.BuildIdentifier("__partial_" + model.GUID.ToString().Replace('-', '_'));
resultAst.Add(AstFactory.BuildAssignment(tmp, rhs));
resultAst.AddRange(
(Definition.ReturnKeys ?? Enumerable.Empty<string>()).Select(
AstFactory.BuildStringNode)
.Select(
(rtnKey, index) =>
AstFactory.BuildAssignment(
model.GetAstIdentifierForOutputIndex(index),
AstFactory.BuildFunctionObject(
"__ComposeBuffered",
3,
new[] { 0, 1 },
new List<AssociativeNode>
{
AstFactory.BuildExprList(
new List<AssociativeNode>
{
AstFactory.BuildFunctionObject(
"__GetOutput",
2,
new[] { 1 },
new List<AssociativeNode>
{
AstFactory.BuildNullNode(),
rtnKey
}),
tmp
}),
AstFactory.BuildIntNode(missingAmt),
AstFactory.BuildNullNode()
}))));
}
示例11: EmitIfStatementNode
private void EmitIfStatementNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.AssociativeGraph.GraphNode graphNode = null)
{
int bp = (int)ProtoCore.DSASM.Constants.kInvalidIndex;
int L1 = (int)ProtoCore.DSASM.Constants.kInvalidIndex;
// If-expr
IfStatementNode ifnode = node as IfStatementNode;
DfsTraverse(ifnode.ifExprNode, ref inferedType, false, graphNode);
L1 = ProtoCore.DSASM.Constants.kInvalidIndex;
bp = pc;
EmitCJmp(L1);
// Create a new codeblock for this block
// Set the current codeblock as the parent of the new codeblock
// Set the new codeblock as a new child of the current codeblock
// Set the new codeblock as the current codeblock
ProtoCore.DSASM.CodeBlock localCodeBlock = new ProtoCore.DSASM.CodeBlock(
context.guid,
ProtoCore.DSASM.CodeBlockType.kConstruct,
Language.NotSpecified,
core.CodeBlockIndex++,
new ProtoCore.DSASM.SymbolTable(GetConstructBlockName("if"), core.RuntimeTableIndex++),
null,
false,
core);
localCodeBlock.instrStream = codeBlock.instrStream;
localCodeBlock.parent = codeBlock;
codeBlock.children.Add(localCodeBlock);
codeBlock = localCodeBlock;
// If-body
foreach (AssociativeNode ifBody in ifnode.IfBody)
{
inferedType = new ProtoCore.Type();
inferedType.UID = (int)PrimitiveType.kTypeVar;
DfsTraverse(ifBody, ref inferedType, false, graphNode);
}
// Restore - Set the local codeblock parent to be the current codeblock
codeBlock = localCodeBlock.parent;
L1 = ProtoCore.DSASM.Constants.kInvalidIndex;
BackpatchTable backpatchTable = new BackpatchTable();
backpatchTable.Append(pc, L1);
EmitJmp(L1);
// Backpatch the L2 destination of the if block
Backpatch(bp, pc);
/*
else if(E) -> traverse E
L1 = pc + 1
L2 = null
bp = pc
emit(jmp, _cx, L1, L2)
{
S -> traverse S
L1 = null
bpTable.append(pc)
emit(jmp,labelEnd)
backpatch(bp,pc)
}
* */
// Elseif-expr
/*
else
{
S -> traverse S
L1 = null
bpTable.append(pc)
emit(jmp,labelEnd)
backpatch(bp,pc)
}
* */
// Else-body
Validity.Assert(null != ifnode.ElseBody);
if (0 != ifnode.ElseBody.Count)
{
// Create a new symboltable for this block
// Set the current table as the parent of the new table
// Set the new table as a new child of the current table
// Set the new table as the current table
// Create a new codeblock for this block
// Set the current codeblock as the parent of the new codeblock
// Set the new codeblock as a new child of the current codeblock
// Set the new codeblock as the current codeblock
localCodeBlock = new ProtoCore.DSASM.CodeBlock(
context.guid,
ProtoCore.DSASM.CodeBlockType.kConstruct,
Language.NotSpecified,
//.........这里部分代码省略.........
示例12: EmitModifierStackNode
private void EmitModifierStackNode(AssociativeNode node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone)
{
if (!IsParsingGlobal() && !IsParsingGlobalFunctionBody() && !IsParsingMemberFunctionBody())
{
return;
}
AssociativeNode prevElement = null;
//core.Options.EmitBreakpoints = false;
ModifierStackNode m = node as ModifierStackNode;
int ci = Constants.kInvalidIndex;
for(int i = 0; i < m.ElementNodes.Count; ++i)
{
bool emitBreakpointForPop = false;
AssociativeNode modifierNode = m.ElementNodes[i];
// Convert Function call nodes into function dot call nodes
if (modifierNode is BinaryExpressionNode)
{
BinaryExpressionNode bnode = modifierNode as BinaryExpressionNode;
if (bnode.LeftNode.Name.StartsWith(ProtoCore.DSASM.Constants.kTempModifierStateNamePrefix))
{
emitBreakpointForPop = true;
}
if (!ProtoCore.Utils.CoreUtils.IsSSATemp(bnode.LeftNode.Name))
{
prevElement = bnode;
}
// Get class index from function call node if it is constructor call
if (bnode.RightNode is FunctionDotCallNode)
{
FunctionDotCallNode fnode = bnode.RightNode as FunctionDotCallNode;
IdentifierNode ident = fnode.DotCall.FormalArguments[0] as IdentifierNode;
string name = "";
if (ident != null)
{
name = ident.Value;
}
ci = core.ClassTable.IndexOf(name);
NodeUtils.SetNodeStartLocation(bnode, fnode.DotCall);
}
// Check if the right node of the modifierNode is a FunctionCall node
else if (bnode.RightNode is FunctionCallNode && ci != Constants.kInvalidIndex)
{
FunctionCallNode rnode = bnode.RightNode as FunctionCallNode;
if (i >= 1)
{
// Use class index to search for function call node and return procedure node
ProcedureNode procCallNode = core.ClassTable.ClassNodes[ci].GetFirstMemberFunctionBy(rnode.Function.Name, rnode.FormalArguments.Count);
// Only if procedure node is non-null do we know its a member function and prefix it with an instance pointer
if (procCallNode != null)
{
////////////////////////////////
BinaryExpressionNode previousElementNode = null;
if (core.Options.GenerateSSA)
{
Validity.Assert(null != prevElement && prevElement is BinaryExpressionNode);
previousElementNode = prevElement as BinaryExpressionNode;
}
else
{
previousElementNode = m.ElementNodes[i - 1] as BinaryExpressionNode;
}
Validity.Assert(null != previousElementNode);
AssociativeNode lhs = previousElementNode.LeftNode;
bnode.RightNode = ProtoCore.Utils.CoreUtils.GenerateCallDotNode(lhs, rnode, core);
FunctionDotCallNode fdcNode = bnode.RightNode as FunctionDotCallNode;
if (fdcNode != null)
{
NodeUtils.SetNodeStartLocation(fdcNode.DotCall, rnode);
}
}
}
}
}
else
{
// We should never get here. Fix it!
Validity.Assert(null != "Unknown node type!");
}
DebugProperties.BreakpointOptions oldOptions = core.DebuggerProperties.breakOptions;
if (emitBreakpointForPop)
{
DebugProperties.BreakpointOptions newOptions = oldOptions;
newOptions |= DebugProperties.BreakpointOptions.EmitPopForTempBreakpoint;
core.DebuggerProperties.breakOptions = newOptions;
}
DfsTraverse(modifierNode, ref inferedType, isBooleanOp, graphNode, subPass);
core.DebuggerProperties.breakOptions = oldOptions;
//.........这里部分代码省略.........
示例13: EmitImportNode
private void EmitImportNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone)
{
ImportNode importNode = node as ImportNode;
CodeBlockNode codeBlockNode = importNode.CodeNode;
string origSourceLocation = core.CurrentDSFileName;
core.CurrentDSFileName = importNode.ModulePathFileName;
this.isEmittingImportNode = true;
// TODO Jun: Merge all the DeltaCompile routines in codegen into one place
bool firstImportInDeltaExecution = false;
int startPC = pc;
if (core.Options.IsDeltaExecution)
{
//ModuleName can be full path as well
if (core.LoadedDLLs.Contains(importNode.ModulePathFileName))
{
return;
}
if (ProtoCore.CompilerDefinitions.Associative.CompilePass.kGlobalFuncBody == compilePass)
{
core.LoadedDLLs.Add(importNode.ModulePathFileName);
firstImportInDeltaExecution = true;
}
}
if (codeBlockNode != null)
{
// Only build SSA for the first time
// Transform after class name compile pass
if (ProtoCore.CompilerDefinitions.Associative.CompilePass.kClassName > compilePass)
{
codeBlockNode.Body = ApplyTransform(codeBlockNode.Body);
codeBlockNode.Body = BuildSSA(codeBlockNode.Body, context);
}
foreach (AssociativeNode assocNode in codeBlockNode.Body)
{
inferedType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0);
if (assocNode is LanguageBlockNode)
{
// Build a binaryn node with a temporary lhs for every stand-alone language block
var iNode = AstFactory.BuildIdentifier(core.GenerateTempLangageVar());
var langBlockNode = AstFactory.BuildAssignment(iNode, assocNode);
DfsTraverse(langBlockNode, ref inferedType, false, null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kUnboundIdentifier);
}
else
{
DfsTraverse(assocNode, ref inferedType, false, null, subPass);
}
}
}
core.CurrentDSFileName = origSourceLocation;
this.isEmittingImportNode = false;
// If in delta execution (a.k.a. LiveRunner) we import an external
// library and at the same time this library generates some
// instructions, we need to keep those instructions to avoid they
// are overwritten in the next run.
if (firstImportInDeltaExecution && pc > startPC)
{
core.deltaCompileStartPC = pc;
}
}
示例14: EmitBinaryExpressionNode
private void EmitBinaryExpressionNode(AssociativeNode node, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, bool isTempExpression = false)
{
BinaryExpressionNode bnode = null;
if (!IsParsingGlobal() && !IsParsingGlobalFunctionBody() && !IsParsingMemberFunctionBody())
return;
bool isBooleanOperation = false;
bnode = node as BinaryExpressionNode;
ProtoCore.Type leftType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0);
ProtoCore.Type rightType = TypeSystem.BuildPrimitiveTypeObject(PrimitiveType.kTypeVar, 0);
DebugProperties.BreakpointOptions oldOptions = core.DebuggerProperties.breakOptions;
// If this is an assignment statement, setup the top level graph node
bool isGraphInScope = false;
if (ProtoCore.DSASM.Operator.assign == bnode.Optr)
{
if (null == graphNode)
{
isGraphInScope = true;
EmitCompileLog("==============Start Node==============\n");
graphNode = new ProtoCore.AssociativeGraph.GraphNode();
graphNode.AstID = bnode.ID;
graphNode.OriginalAstID = bnode.OriginalAstID;
graphNode.exprUID = bnode.ExpressionUID;
graphNode.ssaSubExpressionID = bnode.SSASubExpressionID;
graphNode.ssaExpressionUID = bnode.SSAExpressionUID;
graphNode.IsModifier = bnode.IsModifier;
graphNode.guid = bnode.guid;
graphNode.procIndex = globalProcIndex;
graphNode.classIndex = globalClassIndex;
graphNode.languageBlockId = codeBlock.codeBlockId;
graphNode.ProcedureOwned = bnode.IsProcedureOwned;
//
// Comment Jun:
// If the expression ID of the assignment node in the context execDirtyFlag list is false,
// it means that it was already executed. This needs to be marked as not dirty
if (core.Options.IsDeltaExecution)
{
if (context.exprExecutionFlags.ContainsKey(bnode.ExpressionUID))
{
graphNode.isDirty = context.exprExecutionFlags[bnode.ExpressionUID];
}
}
}
if (bnode.isSSAFirstAssignment)
{
firstSSAGraphNode = graphNode;
}
HandlePointerList(bnode);
if (bnode.LeftNode is IdentifierListNode)
{
// If the lhs is an identifierlist then emit the entire expression here
// This also handles the dependencies of expressions where the lhs is a member variable (this.x = y)
EmitLHSIdentifierListForBinaryExpr(bnode, ref inferedType, isBooleanOp, graphNode, subPass);
if (isGraphInScope)
{
EmitCompileLog("==============End Node==============\n");
}
return;
}
else if (bnode.LeftNode is IdentifierNode)
{
if (bnode.LeftNode.Name.Equals(ProtoCore.DSDefinitions.Keyword.This))
{
string errorMessage = ProtoCore.Properties.Resources.kInvalidThis;
if (localProcedure != null)
{
if (localProcedure.IsStatic)
{
errorMessage = ProtoCore.Properties.Resources.kUsingThisInStaticFunction;
}
else if (localProcedure.ClassID == Constants.kGlobalScope)
{
errorMessage = ProtoCore.Properties.Resources.kInvalidThis;
}
else
{
errorMessage = ProtoCore.Properties.Resources.kAssingToThis;
}
}
core.BuildStatus.LogWarning(WarningID.kInvalidThis, errorMessage, core.CurrentDSFileName, bnode.line, bnode.col, graphNode);
if (isGraphInScope)
{
EmitCompileLog("==============End Node==============\n");
}
return;
}
if (EmitLHSThisDotProperyForBinaryExpr(bnode, ref inferedType, isBooleanOp, graphNode, subPass))
{
if (isGraphInScope)
//.........这里部分代码省略.........
示例15: EmitLHSIdentifierListForBinaryExpr
private void EmitLHSIdentifierListForBinaryExpr(AssociativeNode bnode, ref ProtoCore.Type inferedType, bool isBooleanOp = false, ProtoCore.AssociativeGraph.GraphNode graphNode = null, ProtoCore.CompilerDefinitions.Associative.SubCompilePass subPass = ProtoCore.CompilerDefinitions.Associative.SubCompilePass.kNone, bool isTempExpression = false)
{
BinaryExpressionNode binaryExpr = bnode as BinaryExpressionNode;
if (binaryExpr == null || !(binaryExpr.LeftNode is IdentifierListNode))
{
return;
}
if (ProtoCore.DSASM.Constants.kInvalidIndex == graphNode.updateBlock.startpc)
{
graphNode.updateBlock.startpc = pc;
}
// This is a setter, so disable dependents
graphNode.allowDependents = false;
IdentifierListNode theLeftNode = binaryExpr.LeftNode as IdentifierListNode;
bool isThisPtr = null != theLeftNode.LeftNode.Name && theLeftNode.LeftNode.Name.Equals(ProtoCore.DSDefinitions.Keyword.This);
if (isThisPtr)
{
graphNode.allowDependents = true;
}
ProtoCore.AssociativeGraph.UpdateNodeRef leftNodeRef = AutoGenerateUpdateReference(binaryExpr.LeftNode, graphNode);
ProtoCore.AssociativeGraph.UpdateNodeRef leftNodeArgRef = __To__Deprecate__AutoGenerateUpdateArgumentReference(binaryExpr.LeftNode, graphNode);
ProtoCore.AST.Node lnode = binaryExpr.LeftNode;
NodeUtils.CopyNodeLocation(lnode, binaryExpr);
ProtoCore.AST.Node rnode = binaryExpr.RightNode;
bool isCollapsed = false;
EmitGetterSetterForIdentList(lnode, ref inferedType, graphNode, subPass, out isCollapsed, rnode);
graphNode.allowDependents = true;
// Dependency
if (!isTempExpression)
{
// Dependency graph top level symbol
graphNode.updateNodeRefList.Add(leftNodeRef);
graphNode.updateNodeRefList[0].nodeList[0].dimensionNodeList = graphNode.dimensionNodeList;
// @keyu: foo.id = 42; will generate same leftNodeRef and leftNodeArgRef
if (!isThisPtr && !leftNodeRef.Equals(leftNodeArgRef))
{
graphNode.updateNodeRefList.Add(leftNodeArgRef);
}
//
// If the lhs of the expression is an identifier list, it could have been modified.
// It must then be a dependent of its own graphnode
//
// class C
// {
// x : int;
// constructor C(i:int)
// {
// x = i;
// }
// }
//
// i = 10;
// a = C.C(i);
// a.x = 15; -> re-execute this line ... as 'a' was redefined and its members now changed
// val = a.x;
// i = 7;
//
//
// If inside a member function, and the lhs is a property, make sure it is not just:
// x = y (this.x = y)
//
if (core.Options.LHSGraphNodeUpdate)
{
if (!isThisPtr || graphNode.updateNodeRefList[0].nodeList.Count > 1)
{
ProtoCore.AssociativeGraph.GraphNode dependentNode = new ProtoCore.AssociativeGraph.GraphNode();
dependentNode.isLHSNode = true;
dependentNode.updateNodeRefList.Add(graphNode.updateNodeRefList[0]);
graphNode.dependentList.Add(dependentNode);
}
}
ProtoCore.DSASM.SymbolNode firstSymbol = leftNodeRef.nodeList[0].symbol;
if (null != firstSymbol)
{
EmitDependency(binaryExpr.ExpressionUID, binaryExpr.modBlkUID, false);
}
if (core.Options.GenerateSSA)
{
if (!graphNode.IsSSANode() && !ProtoCore.AssociativeEngine.Utils.IsTempVarLHS(graphNode))
{
// This is the last expression in the SSA'd expression
// Backtrack and assign the this last final assignment graphnode to its associated SSA graphnodes
for (int n = codeBlock.instrStream.dependencyGraph.GraphList.Count - 1; n >= 0; --n)
{
GraphNode currentNode = codeBlock.instrStream.dependencyGraph.GraphList[n];
bool isWithinSameScope = currentNode.classIndex == graphNode.classIndex
//.........这里部分代码省略.........