public ParseResult NarrowedParse(ParseContext ctx, bool tryNarrowContext = false) { var contextToUse = ctx; if (tryNarrowContext && NarrowContextIfPossible(ref contextToUse, out var parseResult)) { return(parseResult); } var skriptTypesManager = WorkspaceManager.CurrentWorkspace.TypesManager; //Split the types (if any) foreach (var typeRaw in Type.Split("/")) { var isObjectType = typeRaw.ToLower() == "object" || typeRaw.ToLower() == "objects"; var skriptType = skriptTypesManager.GetType(typeRaw); //Try to get a known type literal provider for that type var type = WorkspaceManager.Instance.KnownTypesManager.GetTypeByName(typeRaw); ISkriptType skriptTypeDescriptor = null; /*if (!RuntimeHelpers.TryEnsureSufficientExecutionStack()) * return ParseResult.Failure(ctx);*/ //Check if this type requires more than one variable var isMultipleValues = typeRaw.EndsWith("s"); if (isMultipleValues) { //It does so we first have to get the singular type representation for this type //Either get from the name we're given or just subtract the last letter ('s') from it type = WorkspaceManager.Instance.KnownTypesManager.GetTypeByName(typeRaw) ?? WorkspaceManager.Instance.KnownTypesManager.GetTypeByName( typeRaw.Substring(0, typeRaw.Length - 1) ); //If we have a type, replace the type descriptor for the generic multi type matcher if (type != null) // Hand over to GenericMultiValueType { skriptTypeDescriptor = new GenericMultiValueType(type, Constraint, CanMatchListConjunctions); } } else { //We got a single type so, use it. skriptTypeDescriptor = type?.CreateNewInstance(); } IExpression result = null; var oldPos = contextToUse.CurrentPosition; //In case it isn't for an object, always try matching type //if (!isObjectType && (!ctx.Properties.WrappedObjectCount) && !contextToUse.ShouldJustCheckExpressionsThatMatchType) if (isObjectType && ctx.Properties.WrappedObjectCount < 2 || !isObjectType && !contextToUse.ShouldJustCheckExpressionsThatMatchType) { result = skriptTypeDescriptor?.TryParseValue(contextToUse); } //This type has a flag to attempt to match conditionals. So, let's try do just that. if (result == null && Constraint.HasFlagFast(SyntaxValueAcceptanceConstraint.AllowConditionalExpressions)) { foreach (var condition in skriptTypesManager.KnownConditionsFromAddons) { var clone = contextToUse.Clone(false); for (var index = 0; index < condition.PatternNodes.Length; index++) { var conditionPatternNode = condition.PatternNodes[index]; clone.CurrentPosition = contextToUse.CurrentPosition; clone.StartRangeMeasure("Condition"); var conditionResult = conditionPatternNode.Parse(clone); if (conditionResult.IsSuccess) { //Read on real context until our current position on cloned ctx contextToUse.ReadUntilPosition(clone.CurrentPosition); result = new ConditionalExpression(condition, clone.Matches, index, clone.EndRangeMeasure(), contextToUse); } clone.UndoRangeMeasure(); } } } //This type doesn't have a flag to just match literals So, let's try first matching variables. if (result == null && !Constraint.HasFlagFast(SyntaxValueAcceptanceConstraint.LiteralsOnly)) { //Try parsing a variable var reference = new SkriptVariableReferenceType(); var ctxClone = contextToUse.Clone(); try { result = reference.TryParseValue(ctxClone); } catch (Exception) { // ignored } if (result != null) { contextToUse.ReadUntilPosition(ctxClone.CurrentPosition); } } //We have not matched a result. Let's try matching with parentheses if (result == null && !SkipParenthesis) { // Type descriptor wasn't able to parse the literal. Push back and try with parentheses. contextToUse.CurrentPosition = oldPos; //Try parsing with parentheses first var parenthesesType = new GenericParenthesesType(typeRaw); result = parenthesesType.TryParseValue(contextToUse); } //If we didn't match any literal for this type, try to match an expression for this type if (skriptType != null && result == null && !Constraint.HasFlagFast(SyntaxValueAcceptanceConstraint.LiteralsOnly)) { var clone = contextToUse.Clone(false); clone.ShouldJustCheckExpressionsThatMatchType = true; var currentPos = clone.CurrentPosition; result = TryMatchExpressionOnFile(contextToUse, skriptTypesManager, clone, currentPos, skriptType); //Temporarily disable if (false && isObjectType) { //Try matching a Skript expression // Time to check all expressions to make sure the user isn't just trying to mix types for whatever reason... var exprFitType = contextToUse.ShouldJustCheckExpressionsThatMatchType ? skriptTypesManager.GetExpressionsThatCanFitType(skriptType) : skriptTypesManager.KnownExpressionsFromAddons; if (exprFitType != null) { foreach (var expression in exprFitType) { clone.CurrentPosition = currentPos; if (clone.HasVisitedExpression(skriptType, expression)) { continue; } clone.StartRangeMeasure("Expression"); clone.Matches.Clear(); clone.VisitExpression(skriptType, expression); for (var index = 0; index < expression.PatternNodes.Length; index++) { var pattern = expression.PatternNodes[index]; var resultValue = pattern.Parse(clone); if (resultValue.IsSuccess && clone.CurrentPosition >= contextToUse.CurrentPosition) { var range = clone.EndRangeMeasure("Expression"); contextToUse.ReadUntilPosition(clone.CurrentPosition); result = new SkriptExpression(expression, range, contextToUse); } } clone.UndoRangeMeasure(); } } } } //If we have matched something, let's add it to the matches. if (result != null) { if (result.Type == null) { result.Type = skriptTypeDescriptor; } result.Context = contextToUse; var match = new ExpressionParseMatch(result, this); contextToUse.Matches.Add(match); } RestoreFromNarrowedContext(ctx, contextToUse); return(result != null?ParseResult.Success(ctx) : ParseResult.Failure(ctx)); } return(ParseResult.Failure(contextToUse)); }
public ParenthesesExpression(IExpression innerExpression, ISkriptType type) { InnerExpression = innerExpression; Type = type; }