public static bool TryWrite(this IExpression expression, TextWriter writer, Scope scope) { var errors = new List <FluentError>(); if (expression is IInlineExpression inlineExpression) { inlineExpression.Write(writer, scope); } else if (expression is SelectExpression selectExpression) { var selector = selectExpression.Selector.Resolve(scope); if (selector is FluentString or FluentNumber) { foreach (var variant in selectExpression.Variants) { IFluentType key; switch (variant.Type) { case VariantType.NumberLiteral: key = FluentNumber.TryNumber(variant.Key.Span); break; default: key = new FluentString(variant.Key.Span); break; } if (key.Matches(selector, scope)) { variant.Value.Write(writer, scope); return(scope.Errors.Count == 0); } } } for (var i = 0; i < selectExpression.Variants.Count; i++) { var variant = selectExpression.Variants[i]; if (variant.IsDefault) { variant.Value.Write(writer, scope); return(errors.Count == 0); } } errors.Add(ResolverFluentError.MissingDefault()); } return(scope.Errors.Count == 0); }
public static IFluentType Resolve(this IInlineExpression self, Scope scope) { if (self is TextLiteral textLiteral) { StringWriter stringWriter = new(); UnicodeUtil.WriteUnescapedUnicode(textLiteral.Value, stringWriter); return((FluentString)stringWriter.ToString()); } if (self is NumberLiteral numberLiteral) { return(FluentNumber.TryNumber(numberLiteral.Value.Span)); } if (self is VariableReference varRef) { var args = scope.LocalArgs ?? scope.Args; if (args != null && args.TryGetValue(varRef.Id.ToString(), out var arg)) { return(arg.Copy()); } if (scope.LocalArgs == null) { scope.AddError(ResolverFluentError.UnknownVariable(varRef)); } return(new FluentErrType()); } var writer = new StringWriter(); self.TryWrite(writer, scope); return((FluentString)writer.ToString()); }
private static void Write(this IInlineExpression self, TextWriter writer, Scope scope) { if (self is TextLiteral textLiteral) { UnicodeUtil.WriteUnescapedUnicode(textLiteral.Value, writer); return; } if (self is NumberLiteral numberLiteral) { var value = FluentNumber.TryNumber(numberLiteral.Value.Span); value.Write(writer, scope); return; } if (self is MessageReference msgRef) { ProcessMsgRef(self, writer, scope, msgRef); return; } if (self is TermReference termRef) { var res = scope.GetArguments(termRef.Arguments); scope.SetLocalArgs(res.Named); if (scope.Bundle.TryGetAstTerm(termRef.Id.ToString(), out var term)) { var attrName = termRef.Attribute; var attr = term .Attributes .Find(a => a.Id.Equals(attrName)); scope.Track(writer, attr != null ? attr.Value : term.Value, self); } else { scope.WriteRefError(writer, self); } scope.SetLocalArgs(null); return; } if (self is FunctionReference funcRef) { var(resolvedPosArgs, resolvedNamedArgs) = scope.GetArguments(funcRef.Arguments); if (scope.Bundle.TryGetFunction(funcRef.Id, out var func)) { var result = func.Function(resolvedPosArgs, resolvedNamedArgs); if (result.IsError()) { self.WriteError(writer); } else { writer.Write(result.AsString()); } } else { scope.WriteRefError(writer, self); } } if (self is VariableReference varRef) { var id = varRef.Id; var args = scope.LocalArgs ?? scope.Args; if (args != null && args.TryGetValue(id.ToString(), out var arg)) { arg.Write(writer, scope); } else { if (scope.LocalArgs == null) { scope.AddError(ResolverFluentError.Reference(self)); } writer.Write('{'); self.WriteError(writer); writer.Write('}'); } } if (self is Placeable placeable) { placeable.Expression.TryWrite(writer, scope); } }