private Expression ConvertPathInterpolationExpression(ref ProcessedTagTemplateExpression source, FunctionScope escapes, QualifierSpaceId currentQualifierSpaceId, bool isRelativePath) { var expressions = EnumerateTemplateSpans(source.Head, source.TemplateSpans, escapes, currentQualifierSpaceId, isRelativePath: isRelativePath); // Expressions could be empty only for the case like p``; if (expressions == null || expressions.Count == 0) { return(null); } return(new InterpolatedPaths(expressions, isRelativePath, expressions[0].Location)); }
private Expression CurrentPathAtomInterpolationExpression(ref ProcessedTagTemplateExpression source, FunctionScope escapes, QualifierSpaceId currentQualifierSpaceId) { var expressions = EnumerateTaggedExpressionsForPathAtomInterpolation(source.Head, source.TemplateSpans, escapes, currentQualifierSpaceId); // Expressions could be empty only for the case like a``; if (expressions == null || expressions.Count == 0) { return(null); } return(ApplyExpression.Create(m_pathAtomInterpolateSelectorExpression, expressions.ToArray(), expressions[0].Location)); }
private List <Expression> EnumerateTemplateSpans( ITemplateLiteralFragment headNode, INodeArray <ITemplateSpan> templateSpans, FunctionScope escapes, QualifierSpaceId currentQualifierSpaceId, bool isRelativePath) { Contract.Requires(headNode != null); Contract.Requires(templateSpans != null); // Creating a list that will hold all potential expressions List <Expression> result = new List <Expression>((templateSpans.Length * 2) + 1); // Example: 'path/to/{x}/abc/{y}'. // - Head is 'path/to/' // - Spans: // 1. '{x}/abc/': expr 'x', literal '/abc/' // 2. '{y}': expr 'y', no literal. // For instance in this case: p`foo/${x}/${y}` the result equals p`foo`.combine(x).combine(y); // and for this case: p`${x}` the result equals x. // Note that p`path/to/abc` equals as p`./path/to/abc`. Thus for p`${x}/path/to/abc`, x should evaluate to an absolute path, // and such a construct equals x.combine("path").combine("to"). combine("abc"). string head = headNode.Text; if (!string.IsNullOrEmpty(head)) { // Example: 'path/to/' if (!HasTailingPathSeparator(head)) { string message = I($"Path fragment '{head}' does not have a tailing path separator."); RuntimeModelContext.Logger.ReportInvalidPathInterpolationExpression( RuntimeModelContext.LoggingContext, Location(headNode).AsLoggingLocation(), message); return(null); } if (!isRelativePath) { // Tagged expression is expected to be an absolute path. var convertedPathLiteral = m_literalConverter.ConvertPathLiteral( RemoveLeadingAndTailingPathSeparatorIfNeeded(head, isAbsolutePath: true), Location(headNode)); if (convertedPathLiteral == null) { // Error has been reported. return(null); } result.Add(convertedPathLiteral); } else { // Tagged expression is expected to be a relative path. var convertedRelativePathLiteral = m_literalConverter.ConvertRelativePathLiteral( RemoveLeadingAndTailingPathSeparatorIfNeeded(head, isAbsolutePath: false), Location(headNode)); if (convertedRelativePathLiteral == null) { // Error has been reported. return(null); } result.Add(convertedRelativePathLiteral); } } for (int i = 0; i < templateSpans.Length; i++) { //// TODO: Currently fragment is string literal. This somehow defeats the purpose of paths. //// TODO: We need to find a syntactic representation of relative path that differs from string. var span = templateSpans[i]; // Example: span is '{x}/abc/'. if (span.Expression != null) { // Grab 'x' from '{x}/abc/'. var convertedExpression = m_converter.ConvertExpression(span.Expression, escapes, currentQualifierSpaceId); if (convertedExpression != null) { result.Add(convertedExpression); } } // Fragment is '/abc/'. var fragment = span.Literal.Text; // For every expression (except last one), interpolated path should have a separator if (string.IsNullOrEmpty(fragment) && span.Expression != null) { // Fragment is empty or consists only of whitespaces, but expression is present, e.g., span (2) -- '{y}'. if (i == templateSpans.Length - 1) { // Last template span, nothing to do, separator could be empty. continue; } // Not the last template span, thus needs a path separator. string message = "Each path fragment in interpolated path literal should have a path separator between expressions."; RuntimeModelContext.Logger.ReportInvalidPathInterpolationExpression( RuntimeModelContext.LoggingContext, Location(span.Literal).AsLoggingLocation(), message); return(null); } // Skip if fragment is only a separator, e.g., '{w}/{z}'. if (IsPathSeparator(fragment)) { continue; } // Fragments should start with path separator, e.g., '/abc/'. if (!HasLeadingPathSeparator(fragment)) { string message = I($"Path fragment '{fragment}' does not have a leading path separator."); RuntimeModelContext.Logger.ReportInvalidPathInterpolationExpression( RuntimeModelContext.LoggingContext, Location(span.Literal).AsLoggingLocation(), message); return(null); } // All fragments except last one must have a trailing separator, e.g., '/abc/'. if (i != templateSpans.Length - 1 && !HasTailingPathSeparator(fragment)) { string message = I($"Path fragment '{fragment}' does not have a trailing path separator."); RuntimeModelContext.Logger.ReportInvalidPathInterpolationExpression( RuntimeModelContext.LoggingContext, Location(span.Literal).AsLoggingLocation(), message); return(null); } // Remove '/' from '/abc/'. var textFragment = RemoveLeadingAndTailingPathSeparatorIfNeeded(fragment, isAbsolutePath: false); string literal = textFragment.Length == fragment.Length ? fragment : textFragment.ToString(); result.Add(new StringLiteral(literal, LineInfo(span.Literal))); } return(result); }
private Expression ConvertPathAtomInterpolation(ref ProcessedTagTemplateExpression source, FunctionScope escapes, QualifierSpaceId currentQualifierSpaceId) { if (source.Literal != null) { return(m_literalConverter.ConvertPathAtomLiteral(source.Literal, Location(source.TaggedTemplate))); } return(CurrentPathAtomInterpolationExpression(ref source, escapes, currentQualifierSpaceId)); }
/// <summary> /// Coerce source qualifier with a target one. /// </summary> public static bool CoerceQualifierValue( Context context, ModuleLiteral env, QualifierSpaceId sourceQualifierSpaceId, UninstantiatedModuleInfo targetModule, in UniversalLocation referencingLocation,
private List <Expression> EnumerateTaggedExpressionsForStringInterpolation(ITemplateExpression template, FunctionScope escapes, QualifierSpaceId currentQualifierSpaceId) { // Creating a list that will hold all potential expressions List <Expression> result = new List <Expression>((template.TemplateSpans.Length * 2) + 1); var head = template.Head.Text; if (!string.IsNullOrEmpty(head)) { result.Add(LiteralConverter.ConvertStringLiteral(head, Location(template.Head))); } for (int i = 0; i < template.TemplateSpans.Length; i++) { var span = template.TemplateSpans[i]; if (span.Expression != null) { var convertedExpression = m_converter.ConvertExpression(span.Expression, escapes, currentQualifierSpaceId); if (convertedExpression != null) { result.Add(convertedExpression); } } var fragment = span.Literal.Text; if (!string.IsNullOrEmpty(fragment)) { result.Add(LiteralConverter.ConvertStringLiteral(fragment, Location(template.Head))); } } return(result); }
/// <summary> /// Method that converts tagged ast node into <see cref="Expression"/>. /// </summary> public Expression ConvertInterpolation(ITaggedTemplateExpression source, FunctionScope escapes, QualifierSpaceId currentQualifierSpaceId) { (var interpolationKind, ILiteralExpression literal, ITemplateLiteralFragment head, INodeArray <ITemplateSpan> templateSpans) = source; var tagTemplate = new ProcessedTagTemplateExpression(source, interpolationKind, literal, head, templateSpans); switch (interpolationKind) { case InterpolationKind.PathInterpolation: return(ConvertPathInterpolation(ref tagTemplate, escapes, currentQualifierSpaceId)); case InterpolationKind.FileInterpolation: return(ConvertFileInterpolation(ref tagTemplate, escapes, currentQualifierSpaceId)); case InterpolationKind.DirectoryInterpolation: return(ConvertDirectoryInterpolation(ref tagTemplate, escapes, currentQualifierSpaceId)); case InterpolationKind.PathAtomInterpolation: return(ConvertPathAtomInterpolation(ref tagTemplate, escapes, currentQualifierSpaceId)); case InterpolationKind.RelativePathInterpolation: return(ConvertRelativePathInterpolation(ref tagTemplate, escapes, currentQualifierSpaceId)); default: throw Contract.AssertFailure(I($"Unknown interpolation kind '{interpolationKind}'.")); } }
/// <summary> /// Converts string interpolation expression like <code>let x = `${foo}`;</code> /// </summary> public Expression ConvertStringInterpolation(ITemplateExpression source, FunctionScope escapes, QualifierSpaceId currentQualifierSpaceId) { var taggedExpressions = EnumerateTaggedExpressionsForStringInterpolation(source, escapes, currentQualifierSpaceId); // There is one corner cases here: // If tagged expression is just a string literal, but has no expressions, we can just return it if (taggedExpressions.Count == 1) { if (taggedExpressions[0] is StringLiteral stringLiteral) { return(stringLiteral); } } var applyExpression = ApplyExpression.Create(m_stringInterpolationSelectorExpression, taggedExpressions.ToArray(), LineInfo(source)); return(new StringLiteralExpression(applyExpression, applyExpression.Location)); }
private static ObjectLiteral GetQualifierSpaceValue(EvaluationContext context, QualifierSpaceId qualifierSpaceId) { Contract.Requires(context != null); Contract.Requires(context.FrontEndContext.QualifierTable.IsValidQualifierSpaceId(qualifierSpaceId)); var qualifierSpace = context.FrontEndContext.QualifierTable.GetQualifierSpace(qualifierSpaceId); var bindings = new List <Binding>(qualifierSpace.Keys.Count); foreach (var kvp in qualifierSpace.AsDictionary) { var values = ArrayLiteral.CreateWithoutCopy(kvp.Value.Select(s => EvaluationResult.Create(s.ToString(context.StringTable))).ToArray(), default(LineInfo), AbsolutePath.Invalid); bindings.Add(new Binding(kvp.Key, values, default(LineInfo))); } return(ObjectLiteral.Create(bindings, default(LineInfo), AbsolutePath.Invalid)); }
private Expression ConvertDirectoryInterpolation(ref ProcessedTagTemplateExpression source, FunctionScope escapes, QualifierSpaceId currentQualifierSpaceId) { var pathExpression = ConvertPathInterpolation(ref source, escapes, currentQualifierSpaceId); if (pathExpression == null) { // Error occurred. Error was already logged return(null); } return(new DirectoryLiteralExpression(pathExpression, pathExpression.Location)); }
/// <summary> /// Writes a QualifierSpaceId /// </summary> public virtual void Write(QualifierSpaceId value) { Start <QualifierId>(); WriteCompact(value.Id); End(); }
/// <nodoc /> public UninstantiatedModuleInfo(SourceFile sourceFile, [NotNull] FileModuleLiteral fileModuleLiteral, QualifierSpaceId qualifierSpaceId) : this(sourceFile, qualifierSpaceId) { Contract.Requires(fileModuleLiteral != null, "fileModuleLiteral != null"); FileModuleLiteral = fileModuleLiteral; }
/// <nodoc /> // Used only for semantic evaluation public UninstantiatedModuleInfo(SourceFile sourceFile, [NotNull] TypeOrNamespaceModuleLiteral typeOrNamespaceLiteral, QualifierSpaceId qualifierSpaceId) : this(sourceFile, qualifierSpaceId) { Contract.Requires(typeOrNamespaceLiteral != null, "typeOrNamespaceLiteral != null"); TypeOrNamespaceTypeOrNamespaceLiteral = typeOrNamespaceLiteral; }
/// <nodoc/> public WithQualifierExpression(Expression moduleReference, Expression qualifierExpression, QualifierSpaceId sourceQualifierSpaceId, QualifierSpaceId targetQualifierSpaceId, LineInfo location) : base(location) { Contract.Requires(moduleReference != null, "moduleReference != null"); Contract.Requires(qualifierExpression != null, "qualifierExpression != null"); ModuleReference = moduleReference; QualifierExpression = qualifierExpression; SourceQualifierSpaceId = sourceQualifierSpaceId; TargetQualifierSpaceId = targetQualifierSpaceId; }
internal SourceFileParseResult(SourceFile sourceFile, FileModuleLiteral module, QualifierSpaceId qualifierSpaceId) : base(sourceFile) { Contract.Requires(sourceFile != null || module != null, "sourceFile or module should not be null"); SourceFile = sourceFile; Module = module; QualifierSpaceId = qualifierSpaceId; }