public JsNode VisitVariableInitializer(VariableInitializer node) { var tLocal = node.Annotation <LocalResolveResult>(); if (tLocal != null && tLocal.Type != null && tLocal.Type.Kind == TypeKind.Struct && node.ToString() == node.NameToken.ToString() && node.NextSibling.ToString() == ";") { var tType = Type.GetType(tLocal.Type.FullName); //对于基本数据类型,不用new if (tType == null || !tType.IsPrimitive) { var tTypeMember = new JsMemberExpression { Name = tLocal.Type.FullName }; var tCtorMember = new JsMemberExpression { Name = "ctor", PreviousMember = tTypeMember }; var tInvocation = new JsInvocationExpression { Member = tCtorMember }; var tNewObject = new JsNewObjectExpression { Invocation = tInvocation }; return(new JsVariableDeclarator { Name = node.Name, Initializer = tNewObject, }); } } return(new JsVariableDeclarator { Name = node.Name, Initializer = VisitExpression(node.Initializer) }); }
void TransformIntoBaseMethodCallIfNeeded(CSharpInvocationResolveResult res, JsInvocationExpression node2) { var target = res.TargetResult as ThisResolveResult; if (target != null && target.CausesNonVirtualInvocation) //base. { //var info = res.GetInfo(); //var node = info.Nodes.FirstOrDefault(); var ce = target.Type;// node.FindThisEntity(); if (ce != null && Sk.IsExtJsType(ce.GetDefinitionOrArrayType())) { node2.Member = Js.This().Member("callParent"); if (node2.Arguments.IsNotNullOrEmpty()) { node2.Arguments = new List <JsExpression> { Js.NewJsonArray(node2.Arguments.ToArray()) } } ; //var me2 = (node2.Member as JsMemberExpression); //me2.Name = "callParent"; return; } IMethod me2; var me = res.Member; if (me is IProperty) { me2 = ((IProperty)me).Getter; } else if (me is IMethod) { me2 = (IMethod)res.Member; } else { throw new Exception("Can't resolve method from member: " + res.Member); } var member = SkJs.EntityMethodToJsFunctionRef(me2); member = member.Member("call"); node2.Member = member; if (node2.Arguments == null) { node2.Arguments = new List <JsExpression>(); } node2.Arguments.Insert(0, Js.This()); } } void ProcessByRefs1() { ByRefs = new List <ByReferenceResolveResult>(); ByRefIndexes = new List <int>(); RefToRefs = new List <int>(); var c = 0; foreach (var bin in PrmBindings) { var binding = bin.Binding; var byRef = binding.CallResult as ByReferenceResolveResult; if (byRef == null) { c++; continue; } var x = byRef.ElementResult as LocalResolveResult; if (x != null && x.Variable != null && x.Variable.Type.Kind == TypeKind.ByReference) { if (binding.Parameter.IsRef || binding.Parameter.IsOut) { RefToRefs.Add(c); } c++; continue; } ByRefs.Add(byRef); ByRefIndexes.Add(c); c++; } } void ProcessByRefs2() { var c = 0; for (var i = 0; i < Node2.Arguments.Count; i++) { if (Node2.Arguments[i] is JsMemberExpression) { JsMemberExpression jsmex = Node2.Arguments[i] as JsMemberExpression; if (RefToRefs.Contains(i)) { Node2.Arguments[i] = jsmex.PreviousMember; //remove the .Value ref wrapper } else if (ByRefIndexes.Contains(i)) { Node2.Arguments[i] = Js.Member(RefIndexToName(c)); c++; } } else if (Node2.Arguments[i] is JsIndexerAccessExpression) { if (ByRefIndexes.Contains(i)) { Node2.Arguments[i] = Js.Member(RefIndexToName(c)); c++; } } } } void ProcessByRefs3() { if (ByRefs.IsNotNullOrEmpty()) { var func = Js.Function(); //It must assigned to a temporary variable, because typed arrays do not acceppt json. //调整原来使用临时对象.Value的赋值方式,修改为Object.defineProperty定义get|set方法的实现 //临时对象统一调用jsclr里的$Ref方法进行创建 for (var i = 0; i < ByRefs.Count; i++) { var byRef = ByRefs[i]; var expr = VisitExpression(byRef); if (expr is JsMemberExpression) { var memberExpr = expr as JsMemberExpression; if (memberExpr.PreviousMember != null) { var refFuncInvoke = new JsInvocationExpression { Member = new JsMemberExpression { Name = "$Ref" }, Arguments = new List <JsExpression> { memberExpr.PreviousMember, Js.String(memberExpr.Name) } }; func.Add(Js.Var(RefIndexToName(i), refFuncInvoke).Statement()); } else { //如果是局部变量的话使用旧实现方式 var refFuncInvoke = new JsInvocationExpression { Member = new JsMemberExpression { Name = "$Ref" }, Arguments = new List <JsExpression> { Js.Member("null"), memberExpr } }; func.Add(Js.Var(RefIndexToName(i), refFuncInvoke).Statement()); } } else if (expr is JsIndexerAccessExpression) { var indexerExpr = expr as JsIndexerAccessExpression; var indexArg = indexerExpr.Arguments[0]; var refFuncInvoke = new JsInvocationExpression { Member = new JsMemberExpression { Name = "$Ref" }, Arguments = new List <JsExpression> { indexerExpr.Member, indexArg } }; func.Add(Js.Var(RefIndexToName(i), refFuncInvoke).Statement()); } } func.Add(Js.Var("$res", Node2).Statement()); for (var i = 0; i < ByRefs.Count; i++) { var byRef = ByRefs[i]; var memberExpr = VisitExpression(byRef) as JsMemberExpression; if (memberExpr != null && memberExpr.PreviousMember == null) { func.Add(memberExpr.Assign(Js.Member(RefIndexToName(i)).Member("Value")).Statement()); } } func.Add(Js.Return(Js.Member("$res"))); Node2 = Importer.WrapFunctionAndInvoke(Res, func); } }
public JsNode VisitInvocationResolveResult(CSharpInvocationResolveResult res) { Res = res; ProcessMember(); if (MethodAtt != null && MethodAtt.InlineCode != null) { return(Js.CodeExpression(MethodAtt.InlineCode)); } var conditional = ProcessConditional(); if (conditional) { return(null); } bool omittedCalls; var omittedCallsNode = ProcessOmitCalls(out omittedCalls); if (omittedCalls) { return(omittedCallsNode); } JsMember = SkJs.EntityToMember(Member); qiucw.CheckAddInvocation(res, JsMember.Name); ProcessTarget(); ProcessPrmBindings(); ProcessNativeParams(); ProcessByRefs1(); PrmBindings.ForEach(t => t.JsCallResult = VisitExpression(t.Binding.CallResult)); Node2 = new JsInvocationExpression { Member = JsMember, Arguments = PrmBindings.Select(t => t.JsCallResult).ToList(), }; ProcessByRefs2(); ProcessExtensionImplementedInInstance(); TransformIntoBaseMethodCallIfNeeded(Res, Node2); ProcessArgsCustomization(); ProcessGenericMethodArgs(); var inlineCodeExpression = ProcessInlineCodeExpression(); if (inlineCodeExpression != null) { return(inlineCodeExpression); } var omittedDotOperator = ProcessOmitDotOperator(); if (omittedDotOperator != null) { return(omittedDotOperator); } ProcessRemoveEmptyPreviousMemberName(); var indexerAccess = ProcessIndexer(); if (indexerAccess != null) { return(indexerAccess); } ProcessByRefs3(); return(Node2); }
public static StringSegment ParseJsToken(this StringSegment literal, out JsToken token, bool filterExpression) { literal = literal.AdvancePastWhitespace(); if (literal.IsNullOrEmpty()) { token = null; return(literal); } var c = literal.GetChar(0); if (c == '(') { literal = literal.Advance(1); literal = literal.ParseJsExpression(out var bracketsExpr); literal = literal.AdvancePastWhitespace(); c = literal.GetChar(0); if (c == ')') { literal = literal.Advance(1); token = bracketsExpr; return(literal); } throw new SyntaxErrorException($"Expected ')' but instead found '{c}': {literal.SubstringWithElipsis(0, 50)}"); } token = null; c = (char)0; if (literal.IsNullOrEmpty()) { return(TypeConstants.EmptyStringSegment); } var i = 0; literal = literal.AdvancePastWhitespace(); var firstChar = literal.GetChar(0); if (firstChar == '\'' || firstChar == '"' || firstChar == '`' || firstChar == '′') { i = 1; var hasEscapeChar = false; while (i < literal.Length && ((c = literal.GetChar(i)) != firstChar || literal.GetChar(i - 1) == '\\')) { i++; if (!hasEscapeChar) { hasEscapeChar = c == '\\'; } } if (i >= literal.Length || literal.GetChar(i) != firstChar) { throw new SyntaxErrorException($"Unterminated string literal: {literal}"); } var str = literal.Substring(1, i - 1); token = new JsLiteral(str); if (hasEscapeChar) { var sb = StringBuilderCache.Allocate(); for (var j = 0; j < str.Length; j++) { // strip the back-slash used to escape quote char in strings var ch = str[j]; if (ch != '\\' || (j + 1 >= str.Length || str[j + 1] != firstChar)) { sb.Append(ch); } } token = new JsLiteral(StringBuilderCache.ReturnAndFree(sb)); } return(literal.Advance(i + 1)); } if (firstChar >= '0' && firstChar <= '9') { i = 1; var hasExponent = false; var hasDecimal = false; while (i < literal.Length && IsNumericChar(c = literal.GetChar(i)) || (hasExponent = (c == 'e' || c == 'E'))) { if (c == '.') { hasDecimal = true; } i++; if (hasExponent) { i += 2; // [e+1]0 while (i < literal.Length && IsNumericChar(literal.GetChar(i))) { i++; } break; } } var numLiteral = literal.Subsegment(0, i); //don't convert into ternary to avoid Type coercion if (hasDecimal || hasExponent) { token = new JsLiteral(numLiteral.TryParseDouble(out double d) ? d : default(double)); } else { token = new JsLiteral(numLiteral.ParseSignedInteger()); } return(literal.Advance(i)); } if (firstChar == '{') { var props = new List <JsProperty>(); literal = literal.Advance(1); while (!literal.IsNullOrEmpty()) { literal = literal.AdvancePastWhitespace(); if (literal.GetChar(0) == '}') { literal = literal.Advance(1); break; } literal = literal.ParseJsToken(out var mapKeyToken); if (!(mapKeyToken is JsLiteral) && !(mapKeyToken is JsIdentifier)) { throw new SyntaxErrorException($"'{mapKeyToken}' is not a valid Object key, expected literal or identifier."); } JsToken mapValueToken; bool shorthand = false; literal = literal.AdvancePastWhitespace(); if (literal.Length > 0 && literal.GetChar(0) == ':') { literal = literal.Advance(1); literal = literal.ParseJsExpression(out mapValueToken); } else { shorthand = true; if (literal.Length == 0 || (c = literal.GetChar(0)) != ',' && c != '}') { throw new SyntaxErrorException($"Unterminated object literal near: {literal.SubstringWithElipsis(0, 50)}"); } mapValueToken = mapKeyToken; } props.Add(new JsProperty(mapKeyToken, mapValueToken, shorthand)); literal = literal.AdvancePastWhitespace(); if (literal.IsNullOrEmpty()) { break; } if (literal.GetChar(0) == '}') { literal = literal.Advance(1); break; } literal = literal.AdvancePastChar(','); literal = literal.AdvancePastWhitespace(); } token = new JsObjectExpression(props); return(literal); } if (firstChar == '[') { literal = literal.ParseArguments(out var elements, termination: ']'); token = new JsArrayExpression(elements); return(literal); } if (firstChar.IsOperatorChar()) { if (literal.StartsWith(">=")) { token = JsGreaterThanEqual.Operator; return(literal.Advance(2)); } if (literal.StartsWith("<=")) { token = JsLessThanEqual.Operator; return(literal.Advance(2)); } if (literal.StartsWith("!==")) { token = JsStrictNotEquals.Operator; return(literal.Advance(3)); } if (literal.StartsWith("!=")) { token = JsNotEquals.Operator; return(literal.Advance(2)); } if (literal.StartsWith("===")) { token = JsStrictEquals.Operator; return(literal.Advance(3)); } if (literal.StartsWith("==")) { token = JsEquals.Operator; return(literal.Advance(2)); } if (literal.StartsWith("||")) { token = JsOr.Operator; return(literal.Advance(2)); } if (literal.StartsWith("&&")) { token = JsAnd.Operator; return(literal.Advance(2)); } if (literal.StartsWith("<<")) { token = JsBitwiseLeftShift.Operator; return(literal.Advance(2)); } if (literal.StartsWith(">>")) { token = JsBitwiseRightShift.Operator; return(literal.Advance(2)); } switch (firstChar) { case '>': token = JsGreaterThan.Operator; return(literal.Advance(1)); case '<': token = JsLessThan.Operator; return(literal.Advance(1)); case '=': token = JsAssignment.Operator; return(literal.Advance(1)); case '!': token = JsNot.Operator; return(literal.Advance(1)); case '+': token = JsAddition.Operator; return(literal.Advance(1)); case '-': token = JsSubtraction.Operator; return(literal.Advance(1)); case '*': token = JsMultiplication.Operator; return(literal.Advance(1)); case '/': token = JsDivision.Operator; return(literal.Advance(1)); case '&': token = JsBitwiseAnd.Operator; return(literal.Advance(1)); case '|': token = JsBitwiseOr.Operator; return(literal.Advance(1)); case '^': token = JsBitwiseXOr.Operator; return(literal.Advance(1)); case '%': token = JsMod.Operator; return(literal.Advance(1)); default: throw new SyntaxErrorException($"Invalid Operator found near: '{literal.SubstringWithElipsis(0, 50)}'"); } } // identifier var preIdentifierLiteral = literal; literal = literal.ParseIdentifier(out var node); literal = literal.AdvancePastWhitespace(); if (!literal.IsNullOrEmpty()) { c = literal.GetChar(i); if (c == '.' || c == '[') { while (true) { literal = literal.Advance(1); if (c == '.') { literal = literal.AdvancePastWhitespace(); literal = literal.ParseIdentifier(out var property); node = new JsMemberExpression(node, property, computed: false); } else if (c == '[') { literal = literal.AdvancePastWhitespace(); literal = literal.ParseJsExpression(out var property); node = new JsMemberExpression(node, property, computed: true); literal = literal.AdvancePastWhitespace(); if (literal.IsNullOrEmpty() || literal.GetChar(0) != ']') { throw new SyntaxErrorException($"Expected ']' but was '{literal.GetChar(0)}'"); } literal = literal.Advance(1); } literal = literal.AdvancePastWhitespace(); if (literal.IsNullOrWhiteSpace()) { break; } c = literal.GetChar(0); if (c == '(') { throw new SyntaxErrorException("Call expression found on member expression. Only filters can be invoked."); } if (!(c == '.' || c == '[')) { break; } } } else if (c == '(' || (filterExpression && c == ':')) { literal = preIdentifierLiteral.ParseJsCallExpression(out var callExpr, filterExpression: filterExpression); token = callExpr; return(literal); } } token = node; return(literal); }
/// <summary> /// Equalses the specified other. /// </summary> /// <param name="other">The other.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> protected bool Equals(JsMemberExpression other) { return(Equals(Object, other.Object) && Equals(Property, other.Property) && Computed == other.Computed); }