diff --git a/src/WattleScript.Interpreter/Execution/VM/FunctionBuilder.cs b/src/WattleScript.Interpreter/Execution/VM/FunctionBuilder.cs index 9b097e51..7ada1d3d 100755 --- a/src/WattleScript.Interpreter/Execution/VM/FunctionBuilder.cs +++ b/src/WattleScript.Interpreter/Execution/VM/FunctionBuilder.cs @@ -638,4 +638,4 @@ public int Emit_JLclInit(SymbolRef sym, int target) return AppendInstruction(new Instruction(OpCode.JLclInit, target, sym.Index)); } } -} +} \ No newline at end of file diff --git a/src/WattleScript.Interpreter/Extensions.cs b/src/WattleScript.Interpreter/Extensions.cs index ffab3297..c9320c18 100644 --- a/src/WattleScript.Interpreter/Extensions.cs +++ b/src/WattleScript.Interpreter/Extensions.cs @@ -31,4 +31,4 @@ public static string GetSourceFragment(this SourceRef[] refs, string fullSourceC return fullSourceCode.Substring(firstNotNull?.FromCharIndex ?? 0, lastNotNull?.ToCharIndex - firstNotNull?.FromCharIndex ?? 0); } } -} \ No newline at end of file +} diff --git a/src/WattleScript.Interpreter/Serialization/Json/JsonTableConverter.cs b/src/WattleScript.Interpreter/Serialization/Json/JsonTableConverter.cs old mode 100755 new mode 100644 diff --git a/src/WattleScript.Interpreter/Tree/Lexer/Lexer.cs b/src/WattleScript.Interpreter/Tree/Lexer/Lexer.cs old mode 100755 new mode 100644 diff --git a/src/WattleScript.Templating/Extensions.cs b/src/WattleScript.Templating/Extensions.cs new file mode 100644 index 00000000..930f4e33 --- /dev/null +++ b/src/WattleScript.Templating/Extensions.cs @@ -0,0 +1,70 @@ +using System.ComponentModel; +using System; + +namespace WattleScript.Templating; + +internal static class Extensions +{ + public static string ToDescriptionString(this Enum val) + { + DescriptionAttribute[] attributes = (DescriptionAttribute[])val.GetType().GetField(val.ToString())?.GetCustomAttributes(typeof(DescriptionAttribute), false)!; + return attributes.Length > 0 ? attributes[0].Description : ""; + } + + public static T? Peek(this List list) + { + return list.Count > 0 ? list[^1] : default; + } + + public static T? Pop(this List list) + { + if (list.Count > 0) + { + T? itm = list[^1]; + list.RemoveAt(list.Count - 1); + return itm; + } + + return default; + } + + public static void Push(this List list, T? itm) + { + list.Add(itm); + } + + public static string ReplaceFirst(this string text, string search, string replace) + { + int pos = text.IndexOf(search, StringComparison.Ordinal); + return pos < 0 ? text : string.Concat(text[..pos], replace, text.AsSpan(pos + search.Length)); + } + + public static Tuple Snippet(this string str, int pivot, int n) + { + bool clamped = false; + + int expectedStart = pivot - n; + int realStart = Math.Max(0, str.Length > expectedStart ? expectedStart : str.Length); + int expectedLen = 2 * n; + int realLen = Math.Max(str.Length - realStart > expectedLen ? expectedLen : str.Length - realStart, 0); + + if (str.Length - realStart < expectedLen) + { + clamped = true; + } + + string snippet = str.Substring(realStart, realLen); + + /*if (realStart > 0) // text continues before snippet + { + snippet = $"««{snippet}"; + } + + if (str.Length > realStart + realLen) // text continues after snippet + { + snippet = $"{snippet}»»"; + }*/ + + return new Tuple(snippet, clamped); + } +} \ No newline at end of file diff --git a/src/WattleScript.Templating/Parser/Node.cs b/src/WattleScript.Templating/Parser/Node.cs new file mode 100644 index 00000000..ac4f303f --- /dev/null +++ b/src/WattleScript.Templating/Parser/Node.cs @@ -0,0 +1,97 @@ +namespace WattleScript.Templating; + +internal class Document +{ + public List Nodes { get; set; } + public INodeWithChildren CurrentNode { get; set; } + DocumentNode DocNode = new DocumentNode(); + + public Document() + { + Nodes = new List(); + Nodes.Add(DocNode); + CurrentNode = DocNode; + } + + public void AddChild(NodeBase node) + { + DocNode.AddChild(node); + } +} + +internal interface INodeWithChildren +{ + public List Children { get; set; } + public void AddChild(NodeBase child); +} + +internal class NodeBase +{ + public int CharFrom { get; set; } + public bool Recovery { get; set; } + public int Line { get; set; } + public int Col { get; set; } + public int ContentFrom { get; set; } + public int ContentTo { get; set; } +} + +internal class ServerNode : NodeBase +{ + +} + +internal class TextNode : NodeBase +{ + public string Text { get; set; } + + public TextNode(string text) + { + Text = text; + } +} + +internal class DocumentNode : NodeBase, INodeWithChildren +{ + public List Children { get; set; } = new List(); + public void AddChild(NodeBase child) + { + Children.Add(child); + } +} + +internal class HtmlElement : NodeBase, INodeWithChildren +{ + internal enum ClosingType + { + Unknown, + SelfClosing, + ImplicitSelfClosing, + EndTag + } + + public HtmlElement Parent { get; set; } + public List Attributes { get; set; } = new List(); + public string Name { get; set; } + public ClosingType Closing { get; set; } + public bool ForceNativeTag { get; set; } + public List Children { get; set; } = new List(); + + public void AddChild(NodeBase child) + { + Children.Add(child); + } +} + +internal class HtmlAttribute +{ + public string Name { get; set; } + public string Value { get; set; } + public Parser.HtmlAttrEnclosingModes QuoteType { get; set; } + + internal HtmlAttribute(string name, string value, Parser.HtmlAttrEnclosingModes quoteType) + { + Name = name; + Value = value; + QuoteType = quoteType; + } +} \ No newline at end of file diff --git a/src/WattleScript.Templating/Parser/Parser.cs b/src/WattleScript.Templating/Parser/Parser.cs new file mode 100644 index 00000000..dfc8e6fa --- /dev/null +++ b/src/WattleScript.Templating/Parser/Parser.cs @@ -0,0 +1,1747 @@ +using System.Dynamic; +using System.Text; +using System.Text.Json.Serialization; +using Newtonsoft.Json; +using WattleScript.Interpreter; + +namespace WattleScript.Templating; + +internal partial class Parser +{ + enum ImplicitExpressionTypes + { + Literal, + AllowedKeyword, + BannedKeyword + } + + enum Sides + { + Client, + Server + } + + enum StepModes + { + CurrentLexeme, + Buffer + } + + private string? source; + private List Tokens { get; set; } = new List(); + private List Messages { get; set; } = new List(); + private List AllowedTransitionKeywords = new List() {"if", "for", "do", "while", "require", "function", "switch", "enum", "require", "class", "mixin"}; + private List BannedTransitionKeywords = new List() {"else", "elseif"}; + private Dictionary?> KeywordsMap; + private StringBuilder Buffer = new StringBuilder(); + private StringBuilder PooledStringBuilder = new StringBuilder(); + private int pos; + private int lastCommitedPos; + private int lastCommitedLine; + private char c; + private int col; + private int storedLine; + private int storedCol; + private char storedC; + private string storedLexeme; + private StringBuilder currentLexeme = new StringBuilder(); + private int line = 1; + private Script? script; + private StepModes stepMode = StepModes.CurrentLexeme; + private bool parsingTransitionCharactersEnabled = true; + private Document document; + private List openElements = new List(); + private bool parsingBlock = false; + private List fatalExceptions = new List(); + private List recoveredExceptions = new List(); + private TemplatingEngine engine; + private HtmlTagParsingModes tagParsingMode = HtmlTagParsingModes.Native; + internal Table tagHelpersSharedTable; + private string friendlyName; + private int lastKeywordStartPos = 0; + private Dictionary loadedTagHelpers = new Dictionary(); + internal Dictionary pendingTemplateParts = new Dictionary(); + internal Dictionary? tagHelperHints; + private TemplatingEngine.TranspileModes transpileMode => engine.transpileMode; + private TemplatingEngine.TranspileModesExt transpileModeExt = TemplatingEngine.TranspileModesExt.None; + + public Parser(TemplatingEngine engine, Script? script, Table? tagHelpersSharedTable, Dictionary? tagHelperHints) + { + this.engine = engine; + this.script = script; + this.tagHelpersSharedTable = tagHelpersSharedTable ?? new Table(this.script); + this.tagHelperHints = tagHelperHints; + document = new Document(); + + KeywordsMap = new Dictionary?> + { + { "if", ParseKeywordIf }, + { "for", ParseKeywordFor }, + { "while", ParseKeywordWhile }, + { "do", ParseKeywordDo }, + { "function", ParseKeywordFunction }, + { "switch", ParseKeywordSwitch }, + { "else", ParseKeywordInvalidElse }, + { "elseif", ParseKeywordInvalidElseIf }, + { "enum", ParseKeywordEnum }, + { "require", ParseKeywordRequire }, + { "class", ParseKeywordClass }, + { "mixin", ParseKeywordMixin }, + }; + } + + internal List Parse(string templateSource, TemplatingEngine.TranspileModes mode, string friendlyName, TemplatingEngine.TranspileModesExt modeExt, Dictionary loadedTagHelpers) + { + transpileModeExt = modeExt; + this.loadedTagHelpers = loadedTagHelpers; + List tokens = Parse(templateSource, mode, friendlyName); + transpileModeExt = TemplatingEngine.TranspileModesExt.None; + return tokens; + } + + public List Parse(string templateSource, TemplatingEngine.TranspileModes mode, string friendlyName) + { + source = templateSource; + this.friendlyName = friendlyName; + ParseClient(); + + if (IsAtEnd()) + { + AddToken(TokenTypes.Eof); + } + + HandleUnrecoverableErrors(); + return Tokens; + } + + void HandleUnrecoverableErrors() + { + if (fatalExceptions.Count > 0) + { + throw fatalExceptions[0]; + } + } + + bool ParseUntilBalancedChar(char startBr, char endBr, bool startsInbalanced, bool handleStrings, bool handleServerComments) + { + bool inString = false; + char stringChar = ' '; + bool inMultilineComment = false; + + bool InSpecialSequence() + { + return inString || inMultilineComment; + } + + int inbalance = startsInbalanced ? 1 : 0; + + void HandleStringSequence(char chr) + { + string str = GetCurrentLexeme(); + if (LastStoredCharMatches(2, '\\')) // check that string symbol is not escaped + { + return; + } + + if (!InSpecialSequence()) + { + inString = true; + stringChar = chr; + } + else + { + if (stringChar == chr) + { + inString = false; + } + } + } + + while (!IsAtEnd()) + { + Step(); + + if (handleStrings && !inMultilineComment) + { + if (c == '\'') + { + HandleStringSequence('\''); + continue; + } + + if (c == '"') + { + HandleStringSequence('"'); + continue; + } + } + + if (handleServerComments && !inString) + { + if (c == '/' && Peek() == '*') + { + if (!inMultilineComment) + { + inMultilineComment = true; + } + } + else if (c == '*' && Peek() == '/') + { + if (inMultilineComment) + { + inMultilineComment = false; + } + } + } + + if (c == startBr) + { + if (!InSpecialSequence()) + { + inbalance++; + } + } + else if (c == endBr) + { + if (!InSpecialSequence()) + { + inbalance--; + if (inbalance <= 0) + { + return true; + } + } + } + } + + return false; + } + + bool MatchNextNonWhiteSpaceChar(char ch) + { + while (!IsAtEnd()) + { + if (Peek() == ' ') + { + Step(); + } + else if (Peek() == ch) + { + Step(); + return true; + } + else + { + return false; + } + } + + return false; + } + + bool MatchNextNonWhiteSpaceNonNewlineChar(char ch) + { + while (!IsAtEnd()) + { + if (IsWhitespaceOrNewline(Peek())) + { + Step(); + } + else if (Peek() == ch) + { + Step(); + return true; + } + else + { + return false; + } + } + + return false; + } + + bool NextNonWhiteSpaceCharMatches(char ch, int skip = 0) + { + StorePos(); + + for (int i = 0; i < skip; i++) + { + Step(); + } + + while (!IsAtEnd()) + { + if (Peek() == ' ') + { + Step(); + } + else if (Peek() == ch) + { + Step(); + RestorePos(); + return true; + } + else + { + RestorePos(); + return false; + } + } + + RestorePos(); + return false; + } + + bool ParseWhitespaceAndNewlines(Sides currentSide) + { + while (!IsAtEnd()) + { + bool shouldContinue = LookaheadForTransitionClient(currentSide); + if (shouldContinue) + { + continue; + } + + if (IsWhitespaceOrNewline(Peek())) + { + Step(); + continue; + } + + break; + } + + return true; + } + + bool NextLiteralSkipEmptyCharsMatches(string literal, Sides currentSide) + { + if (IsAtEnd()) + { + return false; + } + + StorePos(); + + bool started = false; + while (!IsAtEnd()) + { + bool shouldContinue = LookaheadForTransitionClient(currentSide); + if (shouldContinue) + { + continue; + } + + if (!started) + { + if (Peek() == ' ' || Peek() == '\n' || Peek() == '\r') + { + Step(); + continue; + } + + DiscardCurrentLexeme(); + started = true; + continue; + } + + if (Peek() == ' ' || Peek() == '\n' || Peek() == '\r') + { + break; + } + + Step(); + } + + bool match = literal == GetCurrentLexeme(); + RestorePos(); + + return match; + } + + /// + /// + /// + /// true if we should end current iteration + bool LookaheadForTransitionClient(Sides currentSide) + { + if (!ParsingControlChars()) + { + return false; + } + + TokenTypes transitionType = currentSide == Sides.Client ? TokenTypes.Text : TokenTypes.BlockExpr; + + if (Peek() == '@') + { + if (Peek(2) == '@') // @@ -> @ + { + Step(); + Step(); + RemoveLastCharFromCurrentLexeme(false); + return true; + } + + if (Peek(2) == '*') // @* -> comment + { + AddToken(transitionType); + + Step(); + Step(); + DiscardCurrentLexeme(); + ParseServerComment(); + return true; + } + + AddToken(transitionType); + ParseTransition(currentSide); + return true; + } + + return false; + } + + bool LookaheadForTransitionServerSide() + { + if (!ParsingControlChars()) + { + return false; + } + + if (Peek() == '@' && Peek(2) == ':') + { + AddToken(TokenTypes.BlockExpr); + Step(); + Step(); + DiscardCurrentLexeme(); + ParseRestOfLineAsClient(); + return true; + } + + return false; + } + + void ParseRestOfLineAsClient() + { + char chr = Step(); + while (!IsAtEnd() && chr != '\n' && chr != '\r') + { + bool shouldContinue = LookaheadForTransitionClient(Sides.Client); + if (shouldContinue) + { + continue; + } + + chr = Step(); + } + + AddToken(TokenTypes.Text); + } + + void ParseRestOfLineAsServer() + { + char chr = Step(); + while (!IsAtEnd() && chr != '\n' && chr != '\r') + { + chr = Step(); + } + + AddToken(TokenTypes.BlockExpr); + } + + /* In client mode everything is a literal + * until we encouter @ + * then we lookahead at next char and if it's not another @ (escape) + * we enter server mode + */ + void ParseClient() + { + while (!IsAtEnd()) + { + bool shouldContinue = LookaheadForTransitionClient(Sides.Client); + if (shouldContinue) + { + continue; + } + + shouldContinue = LookaheadForHtmlComment(Sides.Client); + if (shouldContinue) + { + continue; + } + + if (Peek() == '<' && IsHtmlTagOpeningChar(Peek(2))) + { + ParseHtmlTag(null); + continue; + } + + Step(); + } + + AddToken(TokenTypes.Text); + } + + bool IsHtmlTagOpeningChar(char chr) + { + return IsAlpha(chr) || chr == '!'; + } + + // @* *@ + // parser must be positioned directly after opening @* + void ParseServerComment() + { + while (!IsAtEnd()) + { + if (Peek() == '*' && Peek(2) == '@') + { + Step(); + Step(); + RemoveLastCharFromCurrentLexeme(false); + RemoveLastCharFromCurrentLexeme(false); // eat and discard closing *@ + AddToken(TokenTypes.Comment); + break; + } + + Step(); + } + } + + void RemoveLastCharFromCurrentLexeme(bool discardWhitespace) + { + if (GetCurrentLexeme().Length > 0) + { + string str = currentLexeme.ToString()[..^1]; + currentLexeme.Clear(); + currentLexeme.Append(str); + + if (discardWhitespace) + { + if (str.EndsWith('\n') || str.EndsWith('\r') || str.EndsWith(" ") || str.EndsWith('\t') || str.EndsWith('\v') || str.EndsWith('\f')) + { + RemoveLastCharFromCurrentLexeme(discardWhitespace); + } + } + } + } + + bool ParseTransition(Sides currentSide) + { + /* Valid transition sequences are + * @{ - block + * @( - explicit expression + * @: - line transition (back to client) + * @! - explicit escape expression + * @TKeyword - if, for, while, do... + * @TBannedKeyword - else, elseif + * @ConstrainedLiteral - eg. @myVar. First char has to be either alpha or underscore (eg. @8 is invalid) + * --------- + * If a valid transition has not been found + * - if we found TBannedKeyword - we stash an errror, resume parsing client side. We should report: "@ can't be followed by a reserved keyword 'else'. Please remove the @ symbol at line X, char Y." + * - else - we stash an error and consider the sequence to be client side literal. Eg. @8 should report: "@ must be followed by a valid code block" + */ + + Step(); // @ + DiscardCurrentLexeme(); + c = Peek(); + + switch (c) + { + case '{': // code blocks expect to start at { + ParseCodeBlock(false, false); + break; + case '(': + Step(); + DiscardCurrentLexeme(); + ParseExplicitExpression(); + break; + case ':' when currentSide == Sides.Client: + Step(); + DiscardCurrentLexeme(); + ParseRestOfLineAsClient(); + break; + case '!' when currentSide == Sides.Client && NextNonWhiteSpaceCharMatches('{', 1): + Step(); + DiscardCurrentLexeme(); + SetParsingControlChars(false); + ParseCodeBlock(false, false); + SetParsingControlChars(true); + break; + case '#': + Step(); + ParseRestOfLineAsServer(); + break; + default: + { + if (IsAlpha(c)) + { + ParseImplicitExpression(currentSide); + } + else + { + // [todo] either an invalid transition or an annotation + if (currentSide == Sides.Server) + { + // we don't know enough to decide so we treat it as an annotation in server mode for now + currentLexeme.Insert(0, "@"); + return true; + } + + return Throw("Invalid character after @"); + } + + break; + } + } + + return false; + } + + ImplicitExpressionTypes Str2ImplicitExprType(string str) + { + if (AllowedTransitionKeywords.Contains(str)) + { + return ImplicitExpressionTypes.AllowedKeyword; + } + + return BannedTransitionKeywords.Contains(str) ? ImplicitExpressionTypes.BannedKeyword : ImplicitExpressionTypes.Literal; + } + + string ParseLiteral(Sides currentSide) + { + ClearPooledBuilder(); + + while (!IsAtEnd()) + { + bool shouldSkip = LookaheadForTransitionClient(currentSide); + if (shouldSkip) + { + continue; + } + + if (!IsAlphaNumeric(Peek())) + { + break; + } + + char chr = Step(); + PooledStringBuilder.Append(chr); + } + + string str = PooledStringBuilder.ToString(); + ClearPooledBuilder(); + return str; + } + + string ParseLiteralStartsWithAlpha(Sides currentSide) + { + bool first = true; + + while (!IsAtEnd()) + { + bool shouldSkip = LookaheadForTransitionClient(currentSide); + if (shouldSkip) + { + continue; + } + + if (first) + { + if (!IsAlpha(Peek())) + { + break; + } + + first = false; + } + else if (!IsAlphaNumeric(Peek())) + { + break; + } + + char chr = Step(); + PooledStringBuilder.Append(chr); + } + + string str = PooledStringBuilder.ToString(); + ClearPooledBuilder(); + return str; + } + + void ParseExplicitExpression() + { + // parser is positioned after opening ( + ParseUntilBalancedChar('(', ')', true, true, true); + string str = GetCurrentLexeme(); + + // get rid of closing ) + if (str.EndsWith(')')) + { + str = str[..^1]; + } + + currentLexeme.Clear(); + currentLexeme.Append(str); + AddToken(TokenTypes.ExplicitExpr); + } + + void ParseImplicitExpression(Sides currentSide) + { + while (!IsAtEnd()) + { + ParseLiteralStartsWithAlpha(currentSide); + string firstPart = GetCurrentLexeme(); + ImplicitExpressionTypes firstPartType = Str2ImplicitExprType(firstPart); + + // 1. we check for known keywords + if (firstPartType is ImplicitExpressionTypes.AllowedKeyword or ImplicitExpressionTypes.BannedKeyword) + { + ParseKeyword(); + return; + } + + // 2. scan custom directives, if the feature is available + // all directives are parsed as a sequence of oscillating [ALPHA, .] tokens + if (script?.Options.Directives.TryGetValue(firstPart, out _) ?? false) + { + ParseDirective(); + return; + } + + char bufC = Peek(); + if (bufC == '[') + { + ParseUntilBalancedChar('[', ']', false, true, true); + } + else if (bufC == '(') + { + ParseUntilBalancedChar('(', ')', false, true, true); + } + else if (bufC == '.') + { + if (!IsAlpha(Peek(2))) // next char after . has to be alpha else the dot itself is client side + { + break; + } + + Step(); + ParseLiteralStartsWithAlpha(currentSide); + } + + bufC = Peek(); + if (bufC is not ('.' or '(' or '[')) + { + break; + } + } + + AddToken(TokenTypes.ImplicitExpr); + } + + bool ParseKeyword() + { + lastKeywordStartPos = pos; + string keyword = GetCurrentLexeme(); + + // if keyword is from a know list of keywords we invoke a handler method of that keyword + if (KeywordsMap.TryGetValue(keyword, out Func? resolver)) + { + resolver?.Invoke(); + return true; + } + + return false; + } + + /* Here the goal is to find the matching end of transition expression + * and recursively call ourselfs if we encounter a client transfer expression + * We need to understand a subset of ws grammar for this + * - comments (//, multiline) + * - strings ('', "", ``) + * --------- + * We can enter server side in two situations + * - looking for a } in case we've entered from a code block + * - looking for a ) when entered from an explicit expression + */ + bool ParseCodeBlock(bool keepOpeningBrk, bool keepClosingBrk) + { + parsingBlock = true; + bool matchBrk = MatchNextNonWhiteSpaceChar('{'); + + if (matchBrk && !keepOpeningBrk) + { + RemoveLastCharFromCurrentLexeme(false); + } + + AddToken(TokenTypes.BlockExpr); + + int lastPos = pos; + + while (!IsAtEnd()) + { + ParseUntilHtmlOrClientTransition(); + StorePos(); + bool matchedClosingBrk = MatchNextNonWhiteSpaceNonNewlineChar('}'); + + if (matchedClosingBrk) + { + break; + } + + RestorePos(); + + // Safety measure. If something unexpected goes wrong we could deadlock here + if (lastPos == pos) + { + // If we are only one char before end of the stream, we are missing closing } + if (source != null && source.Length - pos <= 1) + { + return Throw("Missing closing } at the of the template"); + } + + return Throw("Internal parser error (infinite loop detected). Please open an issue with the template you are parsing here - https://github.com/WattleScript/wattlescript. We are sorry for the inconvenience."); + } + + lastPos = pos; + } + + if (!keepClosingBrk && currentLexeme.Length > 0) + { + RemoveLastCharFromCurrentLexeme(false); + } + + AddToken(TokenTypes.BlockExpr); + parsingBlock = false; + return true; + } + + bool LastStoredCharMatches(params char[] chars) + { + if (GetCurrentLexeme().Length < 1) + { + return false; + } + + char chr = currentLexeme.ToString()[..^1][0]; + return chars.Contains(chr); + } + + bool LastStoredCharMatches(int n = 1, params char[] chars) + { + if (GetCurrentLexeme().Length < n) + { + return false; + } + + char chr = currentLexeme.ToString().Substring(currentLexeme.Length - 1 - n, 1)[0]; + return chars.Contains(chr); + } + + bool LastStoredCharNotWhitespaceMatches(params char[] chars) + { + string str = GetCurrentLexeme(); + for (int i = str.Length; i > 0; i--) + { + char cc = str[i - 1]; + if (cc == ' ') + { + continue; + } + + return chars.Contains(cc); + } + + return false; + } + + void HandleServerSideSingleLineComment() + { + Step(); + + if (LastStoredCharMatches(1, '\\')) // check that / symbol is not escaped + { + return; + } + + while (!IsAtEnd()) + { + char cc = Step(); + if (cc == '\n') + { + break; + } + } + } + + /* A point of transition can be + * + { + // Next text block to add will be tag's name + // If starting with ! and not doctype or comment (html/cdata), ommit the ! + string str = GetCurrentLexeme(); + if (str.TrimStart().StartsWith("") && subStr != "-" && !subStr.StartsWith("--") && !subStr.StartsWith("[")) + { + DiscardCurrentLexeme(); + currentLexeme.Append(str.ReplaceFirst("!", "")); + } + } + }); + } + + if (offset > 1 && inBuffer) + { + pos += offset - 1; + } + + // Tag name can be provided via a server transition so we have to check for that + LookaheadForTransitionClient(Sides.Client); + + // First char in a proper HTML tag (after opening <) can be [_, !, /, Alpha, ?] + if (!(Peek() == '_' || Peek() == '!' || Peek() == '?' || Peek() == '/' || IsAlpha(Peek()))) + { + Throw("First char after < in an HTML tag must be _, !, / or alpha"); + } + else + { + char chr = Step(); + sb.Append(chr); + } + + // The next few chars represent element's name + while (!IsAtEnd() && IsHtmlTagChar(Peek())) + { + bool shouldContinue = LookaheadForTransitionClient(Sides.Client); + if (shouldContinue) + { + continue; + } + + char chr = Step(); + sb.Append(chr); + } + + if (inBuffer) + { + string tagName = GetBuffer(); + + AddBufferToCurrentLexeme(); + ClearBuffer(false); + SetStepMode(StepModes.CurrentLexeme); + + return tagName; + } + + return sb.ToString(); + } + + bool LookaheadForClosingTag() + { + return Peek() == '>' || (Peek() == '/' && Peek(2) == '>'); + } + + bool ParseHtmlTag(HtmlElement? parentElement) + { + ParseWhitespaceAndNewlines(Sides.Client); + AddToken(TokenTypes.Text); + + if (Peek() != '<') + { + return false; + } + + HtmlElement el = new HtmlElement() {CharFrom = pos, Line = line, Col = col}; + char chr = Step(); // has to be < + string tagName = ParseHtmlTagName(false); + el.Name = tagName; + openElements.Push(el); + + if (tagParsingMode == HtmlTagParsingModes.Native && engine.tagHelpersMap.ContainsKey(tagName.ToLowerInvariant())) + { + return ParseTagHelper(el); + } + + ParseWhitespaceAndNewlines(Sides.Client); + + while (!IsAtEnd()) + { + bool shouldContinue = LookaheadForTransitionClient(Sides.Client); + if (shouldContinue) + { + continue; + } + + bool shouldEnd = LookaheadForAttributeOrClose(tagName, false, el, true); + if (shouldEnd) + { + break; + } + } + + return true; + } + + int ScanForElementClosingTag(HtmlElement el) + { + ParseHtmlOrPlaintextUntilClosingTag(el.Name, el); + + return el.ContentTo; + } + + bool ParseTagHelper(HtmlElement el) + { + // parser is located after name in a tag + // 0. the process starts the same as with native tag helpers + DiscardCurrentLexeme(); + tagParsingMode = HtmlTagParsingModes.TagHelper; + + // 1. parse until end of opening tag-helper tag + ParseWhitespaceAndNewlines(Sides.Client); + while (!IsAtEnd()) + { + bool shouldContinue = LookaheadForTransitionClient(Sides.Client); + if (shouldContinue) + { + continue; + } + + bool shouldEnd = LookaheadForAttributeOrClose(el.Name, false, el, false); + if (shouldEnd) + { + break; + } + } + + // 2. if tag-helper is not self closing, scan for end of its content + if (el.Closing != HtmlElement.ClosingType.SelfClosing) + { + el.ContentTo = ScanForElementClosingTag(el); + } + + DynValue tagHelpersDataDv = DynValue.NewTable(tagHelpersSharedTable); + + Table ctxTable = new Table(engine.script); + ctxTable.Set("data", tagHelpersDataDv); + + TagHelper helper = engine.tagHelpersMap[el.Name.ToLowerInvariant()]; + int contentFrom = el.ContentFrom; + int contentTo = el.ContentTo; + string contentStr = contentTo > 0 ? source.Substring(contentFrom, contentTo - contentFrom) : ""; + + engine.script.Globals.Set("__tagData", tagHelpersDataDv); + ctxTable.Set("content", DynValue.NewString(contentStr)); + + Table attrTable = new Table(engine.script); + foreach (HtmlAttribute attr in el.Attributes) + { + attrTable.Set(attr.Name, DynValue.NewString(attr.Value)); + } + + DynValue fAttrTable = DynValue.NewTable(attrTable); + ctxTable.Set("attributes", fAttrTable); + + // 3. before resolving a tag-helper, we need to resolve the part of template currently transpiled + Token t = null; + + string pendingTemplate = engine.Transform(Tokens); + if (!string.IsNullOrWhiteSpace(pendingTemplate)) + { + if (transpileMode == TemplatingEngine.TranspileModes.Run) + { + if (tagHelperHints?.ContainsKey(pendingTemplate) ?? false) + { + using MemoryStream ms = new MemoryStream(tagHelperHints[pendingTemplate]); + engine.script.DoStream(ms); + } + else + { + DynValue dv = engine.script.LoadString(pendingTemplate); + engine.script.Call(dv); + + if (!pendingTemplateParts.ContainsKey(pendingTemplate)) + { + pendingTemplateParts.Add(pendingTemplate, dv); + } + } + } + else + { + t = AddAdHocToken(TokenTypes.BlockExpr, pendingTemplate); + } + } + + Tokens.Clear(); + + if (t != null) + { + Tokens.Add(t); // in case we are dumping + } + + void DumpTagHelper() + { + if (loadedTagHelpers.Count == 0) + { + AddAdHocToken(TokenTypes.BlockExpr, "__tagHelperCtxTable = {data: [], content: \"\", attributes: []};\n"); // shared table between tag helpers + } + + StringBuilder attrBuilder = new StringBuilder(); + attrBuilder.Append('{'); + int i = 0; + foreach (HtmlAttribute attr in el.Attributes) + { + attrBuilder.Append($"{attr.Name}: `{attr.Value.Replace("`", "\\`")}`"); + + if (i < el.Attributes.Count - 1) + { + attrBuilder.Append(','); + } + + i++; + } + + attrBuilder.Append('}'); + + if (!loadedTagHelpers.ContainsKey(helper)) + { + AddAdHocToken(TokenTypes.BlockExpr, $"{helper.Template}"); + loadedTagHelpers.Add(helper, true); + } + + string dumpedContent = engine.TranspileRecursive(contentStr, loadedTagHelpers); + + // update context for this tag instance + AddAdHocToken(TokenTypes.BlockExpr, $"__tagHelperCtxTable[\"content\"] = () => {{\n{dumpedContent}\n}};"); + AddAdHocToken(TokenTypes.BlockExpr, $"__tagHelperCtxTable[\"attributes\"] = {attrBuilder};"); + + AddAdHocToken(TokenTypes.BlockExpr, $"{helper.FunctionName}(__tagHelperCtxTable);"); + } + + // 4. if dispatching method is not yet loaded, we load it. Then we call it + if (loadedTagHelpers.ContainsKey(helper)) + { + if (transpileMode == TemplatingEngine.TranspileModes.Dump) + { + DumpTagHelper(); + } + else + { + engine.script.Globals.Get(helper.FunctionName).Function.Call(ctxTable); + } + } + else + { + if (transpileMode == TemplatingEngine.TranspileModes.Dump) + { + DumpTagHelper(); + } + else + { + engine.script.DoString(helper.Template); + engine.script.Globals.Get(helper.FunctionName).Function.Call(ctxTable); + } + + if (!loadedTagHelpers.ContainsKey(helper)) + { + loadedTagHelpers.Add(helper, true); + } + } + + engine.script.Globals["stdout"] = engine.Print; + + // tag output is already in stdout + tagParsingMode = HtmlTagParsingModes.Native; + return true; + } + + bool LookaheadForAttributeOrClose(string tagName, bool startsFromClosingTag, HtmlElement? el, bool parseContent) + { + if (LookaheadForClosingTag()) + { + CloseTag(tagName, startsFromClosingTag, el, parseContent); + return true; + } + + return ParseAttribute(tagName, startsFromClosingTag, el, parseContent); + } + + string ParseAttributeName() + { + ParseWhitespaceAndNewlines(Sides.Client); + + StringBuilder sb = new StringBuilder(); + while (!IsAtEnd()) + { + bool shouldContinue = LookaheadForTransitionClient(Sides.Client); + if (shouldContinue) + { + continue; + } + + if (Peek() == '=' || LookaheadForClosingTag()) + { + return sb.ToString(); + } + + sb.Append(Step()); + } + + return sb.ToString(); + } + + Tuple ParseAttributeValue() + { + HtmlAttrEnclosingModes closeMode = HtmlAttrEnclosingModes.None; + StringBuilder sb = new StringBuilder(); + + if (Peek() == '\'') + { + closeMode = HtmlAttrEnclosingModes.SingleQuote; + Step(); + } + else if (Peek() == '\"') + { + closeMode = HtmlAttrEnclosingModes.DoubleQuote; + Step(); + } + + while (!IsAtEnd()) + { + bool shouldContinue = LookaheadForTransitionClient(Sides.Client); + if (shouldContinue) + { + continue; + } + + if (IsWhitespaceOrNewline(Peek()) && closeMode == HtmlAttrEnclosingModes.None) + { + return new Tuple(sb.ToString(), HtmlAttrEnclosingModes.None); + } + + if (Peek() == '\'' && closeMode == HtmlAttrEnclosingModes.SingleQuote) + { + Step(); + return new Tuple(sb.ToString(), HtmlAttrEnclosingModes.SingleQuote); + } + + if (Peek() == '"' && closeMode == HtmlAttrEnclosingModes.DoubleQuote) + { + Step(); + return new Tuple(sb.ToString(), HtmlAttrEnclosingModes.DoubleQuote); + } + + sb.Append(Step()); + } + + return new Tuple(sb.ToString(), HtmlAttrEnclosingModes.Unknown); + } + + + bool ParseAttribute(string tagName, bool startsFromClosingTag, HtmlElement el, bool parseTagContent) + { + string name = ParseAttributeName(); + + if (Peek() == '=') + { + Step(); + Tuple val = ParseAttributeValue(); + el.Attributes.Add(new HtmlAttribute(name, val.Item1, val.Item2)); + } + + if (LookaheadForClosingTag()) + { + CloseTag(tagName, startsFromClosingTag, el, parseTagContent); + return true; + } + + return false; + } + + bool CloseTag(string tagName, bool startsFromClosingTag, HtmlElement? el, bool parseTagContent) + { + if (Peek() == '/' && Peek(2) == '>') + { + Step(); + Step(); + + if (el != null) + { + el.Closing = HtmlElement.ClosingType.SelfClosing; + } + } + else if (Peek() == '>') + { + Step(); + + if (el != null) + { + el.Closing = HtmlElement.ClosingType.EndTag; + } + } + + bool parseContent = false; + string tagText = GetCurrentLexeme(); + + if (el != null) + { + if (!startsFromClosingTag) + { + el.ContentFrom = pos; + } + } + + if (tagParsingMode == HtmlTagParsingModes.TagHelper) + { + DiscardCurrentLexeme(); + } + + if (!parseTagContent) + { + return true; + } + + if (!startsFromClosingTag) + { + bool isSelfClosing = IsSelfClosingHtmlTag(tagName); + bool isSelfClosed = CurrentLexemeIsSelfClosedHtmlTag(); + bool startsWithSlash = tagName.StartsWith('/'); + + parseContent = !isSelfClosed && !isSelfClosing && !startsWithSlash; + + if (parseContent) + { + if (tagText == "") // "" has a special meaning only when exactly matched. Any modification like "" will be rendered as a normal tag + { + DiscardCurrentLexeme(); + ParseHtmlOrPlaintextUntilClosingTag(tagName, el); + } + else if (tagName is "script" or "style") // raw text elements + { + ParsePlaintextUntilClosingTag(tagName); + ParseHtmlClosingTag(tagName, el, false); + } + else + { + ParseHtmlOrPlaintextUntilClosingTag(tagName, el); + } + } + else + { + HtmlElement? ell = openElements.Peek(); + if (ell == el) + { + openElements.Pop(); + } + } + } + + string s = GetCurrentLexeme(); + + if (startsFromClosingTag && tagName == "/text" && s.Trim() == "" && el != null && source?.Substring(el.CharFrom, 6) == "") // + { + DiscardCurrentLexeme(); + return parseContent; + } + + if (tagParsingMode == HtmlTagParsingModes.Native) + { + AddToken(TokenTypes.Text); + } + else + { + DiscardCurrentLexeme(); + } + + return parseContent; + } + + // parser has to be positioned at opening < of the closing tag + string ParseHtmlClosingTag(string openingTagName, HtmlElement? el, bool inBuffer) + { + ParseWhitespaceAndNewlines(Sides.Client); + if (Peek() != '<') + { + return ""; + } + + char chr = Step(); // has to be < + string closingTagName = ParseHtmlTagName(inBuffer); + + //ParseUntilBalancedChar('<', '>', true, true, true); + + while (!IsAtEnd()) + { + bool shouldContinue = LookaheadForTransitionClient(Sides.Client); + if (shouldContinue) + { + continue; + } + + bool shouldEnd = LookaheadForAttributeOrClose(closingTagName, true, el, true); + if (shouldEnd) + { + break; + } + } + + if ($"/{openingTagName}" != closingTagName) + { + // [todo] end tag does not match opening tag + // we will be graceful but a warning can be emmited + } + + return closingTagName; + } + + void ParsePlaintextUntilClosingTag(string openingTagName) + { + while (!IsAtEnd()) + { + bool shouldContinue = LookaheadForTransitionClient(Sides.Client); + if (shouldContinue) + { + continue; + } + + if (Peek() == '<' && Peek(2) == '/') + { + if (PeekRange(3, openingTagName.Length) == openingTagName) + { + break; + } + } + + Step(); + } + } + + void ParseHtmlOrPlaintextUntilClosingTag(string openingTagName, HtmlElement el) + { + AddToken(TokenTypes.Text); + + while (!IsAtEnd()) + { + bool shouldContinue = LookaheadForTransitionClient(Sides.Client); + if (shouldContinue) + { + continue; + } + + shouldContinue = LookaheadForHtmlComment(Sides.Client); + if (shouldContinue) + { + continue; + } + + if (el.Recovery) + { + AddToken(TokenTypes.Text); + return; + } + + if (Peek() == '<') + { + if (Peek(2) == '/' && IsHtmlTagOpeningChar(Peek(3))) + { + AddToken(TokenTypes.Text); + + string closingNameLookahead = ParseHtmlTagName(true, 3); // skip 0) + { + // [todo] + // here two actions can take place based on the context + // 1) peeked element is superfluous and doesn't have an opening element ->
+ // 2) peeked element encloses another element that is already in opened elements ->
+ if (openElements.FirstOrDefault(x => string.Equals(x?.Name, closingNameLookahead, StringComparison.InvariantCultureIgnoreCase)) == null) + { + ParseHtmlTag(el); + } + else + { + HtmlElement? rel = openElements.Pop(); + if (rel != null) + { + rel.Recovery = true; + } + } + } + + AddToken(TokenTypes.Text); + return; + } + + if (IsHtmlTagOpeningChar(Peek(2))) + { + ParseHtmlTag(el); + continue; + } + } + + Step(); + } + + if (parsingBlock) + { + FatalIfInBlock($"Unclosed element {el.Name} at line {el.Line}, {el.Col}. Parser could not recover from this error."); + } + } + + bool LookaheadForHtmlComment(Sides currentSide) + { + if (Peek() == '<' && Peek(2) == '!') + { + if (Peek(3) == '-' && Peek(4) == '-') + { + ParseHtmlComment(HtmlCommentModes.DoubleHyphen, currentSide); + return true; + } + + if (Peek(3) == '[') + { + ParseHtmlComment(HtmlCommentModes.Cdata, currentSide); + return true; + } + } + + return false; + } + + void ParseHtmlComment(HtmlCommentModes openCommentMode, Sides currentSide) + { + int startLine = line; + int startCol = col; + + if (currentSide == Sides.Server) + { + AddToken(TokenTypes.BlockExpr); + } + + if (openCommentMode == HtmlCommentModes.DoubleHyphen) + { + StepN(4); // + { + StepN(3); + AddToken(TokenTypes.Text); + return; + } + + if (openCommentMode == HtmlCommentModes.Cdata && Peek() == ']' && Peek(2) == ']' && Peek(3) == '>') // ]]> + { + StepN(3); + AddToken(TokenTypes.Text); + return; + } + + bool shouldContinue = LookaheadForTransitionClient(Sides.Client); + if (shouldContinue) + { + continue; + } + + Step(); + } + + // [todo] error, unclosed html comment + FatalIfInBlock($"Unclosed HTML comment at line {startLine}, {startCol}. Parser could not recover from this error."); + } +} \ No newline at end of file diff --git a/src/WattleScript.Templating/Parser/ParserKeywords.cs b/src/WattleScript.Templating/Parser/ParserKeywords.cs new file mode 100644 index 00000000..8298a7bc --- /dev/null +++ b/src/WattleScript.Templating/Parser/ParserKeywords.cs @@ -0,0 +1,370 @@ +using WattleScript.Interpreter; + +namespace WattleScript.Templating; + +internal partial class Parser +{ + // @else {} + // parser has to be positioned after else + bool ParseKeywordInvalidElse() + { + return Throw("Found \"@else\". Please remove the leading @. Keywords else, elseif shouldn't be prefixed with @."); + } + + // @elseif {} + // parser has to be positioned after elseif + bool ParseKeywordInvalidElseIf() + { + return Throw("Found \"@elseif\". Please remove the leading @. Keywords else, elseif shouldn't be prefixed with @."); + } + + // if (expr) {} + // parser has to be positioned after if, either at opening ( or at whitespace before it + bool ParseKeywordIf() + { + ParseGenericBrkKeywordWithBlock("if"); + + bool matchesElse = NextLiteralSkipEmptyCharsMatches("else", Sides.Server) || NextLiteralSkipEmptyCharsMatches("elseif", Sides.Server); // else handles "else if" but we have to check for "elseif" manually + if (matchesElse) + { + ParseKeywordElseOrElseIf(); + } + + return false; + } + + // @require "lib" + // parser has to be positioned after require + bool ParseKeywordRequire() + { + ParseWhitespaceAndNewlines(Sides.Server); + if (!MatchNextNonWhiteSpaceChar('"')) + { + return Throw("Expected \" after @require"); + } + + ParseLiteral(Sides.Server); + + if (!MatchNextNonWhiteSpaceChar('"')) + { + return Throw("Expected \" after ident end at @require"); + } + + ParseWhitespaceAndNewlines(Sides.Server); + + AddToken(TokenTypes.BlockExpr); + return true; + } + + // class A : B with C, D {} + // parser has to be positioned after "class" + bool ParseKeywordClass() + { + ParseWhitespaceAndNewlines(Sides.Server); + string className = ParseLiteralStartsWithAlpha(Sides.Server); // class name + ParseWhitespaceAndNewlines(Sides.Server); + + if (string.IsNullOrWhiteSpace(className)) + { + Throw("Class name has to start with ALPHA character"); + } + + if (NextNonWhiteSpaceCharMatches(':')) + { + Step(); // : + ParseWhitespaceAndNewlines(Sides.Server); + string baseName = ParseLiteralStartsWithAlpha(Sides.Server); // base name + + if (string.IsNullOrWhiteSpace(baseName)) + { + Throw("Base name in class definition has to start with ALPHA character"); + } + } + + if (NextNonWhiteSpaceCharMatches('{')) + { + AddToken(TokenTypes.BlockExpr); + ParseGenericKeywordWithBlock("class"); + AddToken(TokenTypes.BlockExpr); + return true; + } + + ParseWhitespaceAndNewlines(Sides.Server); + string withCandidate = ParseLiteralStartsWithAlpha(Sides.Server); // with + + if (withCandidate != "with") + { + Throw("Expected \"with\" in class declaration"); + } + + void ParseMixin() + { + ParseWhitespaceAndNewlines(Sides.Server); + string mixinName = ParseLiteralStartsWithAlpha(Sides.Server); // mixin n + + if (string.IsNullOrWhiteSpace(mixinName)) + { + Throw("Mixin name in class definition has to start with ALPHA character"); + } + + if (NextNonWhiteSpaceCharMatches(',')) + { + Step(); // , + ParseMixin(); + } + } + + ParseMixin(); + + if (NextNonWhiteSpaceCharMatches('{')) + { + ParseGenericKeywordWithBlock("class"); + AddToken(TokenTypes.BlockExpr); + return true; + } + + Throw($"Malformated class definition: {source?.Substring(lastKeywordStartPos, pos) ?? ""}"); + return false; + } + + // mixin Mixin {} + // parser has to be positioned after "mixin" + bool ParseKeywordMixin() + { + return ParseGenericKeywordWithIdentBlock("mixin"); + } + + // enum Enum {} + // parser has to be positioned after "enum", at name Ident + bool ParseKeywordEnum() + { + return ParseGenericKeywordWithIdentBlock("enum"); + } + + // for (i in a..b) + // for (i = 0; i < x; i++) + // for (;;) + // we always have () around expr/s + // parser has to be positioned after "for", either at opening ( or at a whitespace preceding it + bool ParseKeywordFor() + { + return ParseGenericBrkKeywordWithBlock("for"); + } + + // while (i in a..b) {} + // parser has to be positioned after "while", either at opening ( or at a whitespace preceding it + bool ParseKeywordWhile() + { + return ParseGenericBrkKeywordWithBlock("while"); + } + + // switch (expr) {} + // parser has to be positioned after "switch", either at opening ( or at a whitespace preceding it + bool ParseKeywordSwitch() + { + return ParseGenericBrkKeywordWithBlock("switch"); + } + + // do {} while () + // parser has to be positioned after "do", either at opening { or at a whitespace preceding it + bool ParseKeywordDo() + { + bool doParsed = ParseGenericKeywordWithBlock("do"); + bool matchesWhile = NextLiteralSkipEmptyCharsMatches("while", Sides.Server); + + if (matchesWhile) + { + ParseWhitespaceAndNewlines(Sides.Server); + string whileStr = StepN(5); + bool whileParsed = ParseGenericBrkKeywordWithoutBlock("while"); + + if (whileParsed) + { + AddToken(TokenTypes.BlockExpr); + } + } + + return doParsed; + } + + // function foo() {} + // parser has to be positioned after "function", either at first ALPHA char of the function's name or whitespace preceding it + bool ParseKeywordFunction() + { + ParseWhitespaceAndNewlines(Sides.Server); + + char chr = Peek(); + if (chr == '(') + { + return Throw("Missing function's name"); + } + + if (chr == '{') + { + return Throw("Missing function's name and signature"); + } + + if (!IsAlpha(chr)) + { + return Throw("First char in function's name has to be an alpha character"); + } + + string fnName = ParseLiteral(Sides.Server); + + if (string.IsNullOrWhiteSpace(fnName)) + { + return Throw("Missing function's name"); + } + + return ParseGenericBrkKeywordWithBlock("function"); + } + + // directive [a.b.c]? + // parser has to be positioned after "directive", before optional right hand + bool ParseDirective() + { + ParseWhitespaceAndNewlines(Sides.Server); + + // no right hand or invalid right hand + if (!IsAlpha(Peek())) + { + AddToken(TokenTypes.BlockExpr); + return true; + } + + while (!IsAtEnd()) + { + ParseLiteral(Sides.Server); + + if (Peek() == '.') + { + Step(); + } + + if (!IsAlpha(Peek())) + { + break; + } + } + + AddToken(TokenTypes.BlockExpr); + return true; + } + + // keyword () {} + bool ParseGenericBrkKeywordWithBlock(string keyword) + { + bool openBrkMatched = MatchNextNonWhiteSpaceChar('('); + + if (!openBrkMatched) + { + Throw($"Expected '(' after {keyword}"); + } + + bool endExprMatched = ParseUntilBalancedChar('(', ')', true, true, true); + + if (!endExprMatched) + { + return false; + } + + ParseCodeBlock(true, true); + return true; + } + + // keyword IDENT {} + bool ParseGenericKeywordWithIdentBlock(string keyword) + { + ParseWhitespaceAndNewlines(Sides.Client); + string ident = ParseLiteralStartsWithAlpha(Sides.Client); + + if (string.IsNullOrWhiteSpace(ident)) // ident starts with non Alpha + { + return Throw($"Expected enum name starting with Alpha, got {Peek()}"); + } + + return ParseGenericKeywordWithBlock(keyword); + } + + // keyword {} + bool ParseGenericKeywordWithBlock(string keyword) + { + bool openBrkMatched = MatchNextNonWhiteSpaceChar('{'); + + if (!openBrkMatched) + { + Throw($"Expected {{ after {keyword}"); + } + + ParseCodeBlock(true, true); + return true; + } + + // keyword () + bool ParseGenericBrkKeywordWithoutBlock(string keyword) + { + bool openBrkMatched = MatchNextNonWhiteSpaceChar('('); + + if (!openBrkMatched) + { + Throw($"Expected ( after {keyword}"); + } + + bool endExprMatched = ParseUntilBalancedChar('(', ')', true, true, true); + return endExprMatched; + } + + // else {} + // or possibly else if () {} + bool ParseKeywordElseOrElseIf() + { + StorePos(); + ParseWhitespaceAndNewlines(Sides.Server); + string elseStr = StepN(4); + ParseWhitespaceAndNewlines(Sides.Server); + string elseIfStr = StepN(2); + RestorePos(); + + if (elseStr == "else" && elseIfStr == "if") + { + ParseKeywordElseIf(); + } + else if (elseStr == "else") + { + ParseKeywordElse(); + } + + return true; + } + + // else if () {} + bool ParseKeywordElseIf() + { + ParseWhitespaceAndNewlines(Sides.Server); + string elseStr = StepN(4); // eat else + ParseWhitespaceAndNewlines(Sides.Server); + string elseIfStr = StepN(2); // ear if + + return ParseKeywordIf(); + } + + // else {} + bool ParseKeywordElse() + { + ParseWhitespaceAndNewlines(Sides.Server); + //DiscardCurrentLexeme(); + + string elseStr = StepN(4); + + if (elseStr != "else") + { + return false; + } + + string str = GetCurrentLexeme(); + + ParseCodeBlock(true, true); + + return false; + } +} \ No newline at end of file diff --git a/src/WattleScript.Templating/Parser/ParserUtils.cs b/src/WattleScript.Templating/Parser/ParserUtils.cs new file mode 100644 index 00000000..413470f6 --- /dev/null +++ b/src/WattleScript.Templating/Parser/ParserUtils.cs @@ -0,0 +1,401 @@ +using System.Runtime.InteropServices; + +namespace WattleScript.Templating; + +internal partial class Parser +{ + private Dictionary AddTokenActions = new Dictionary(); + + internal enum HtmlAttrEnclosingModes + { + Unknown, + None, + SingleQuote, + DoubleQuote + } + + internal enum HtmlCommentModes + { + DoubleHyphen, // + Cdata // or --> + } + + internal enum HtmlTagParsingModes + { + Native, + TagHelper + } + + void ClearPooledBuilder() + { + PooledStringBuilder.Clear(); + } + + bool IsAtEnd() + { + return pos >= source.Length; + } + + string GetCurrentLexeme() + { + return currentLexeme.ToString(); + } + + bool IsAlphaNumeric(char ch) + { + return IsDigit(ch) || IsAlpha(ch); + } + + bool IsHtmlTagChar(char ch) + { + return IsAlphaNumeric(ch) || ch == ':' || ch == '-'; + } + + bool IsAlpha(char ch) + { + return char.IsLetter(ch) || ch is '_'; + } + + bool IsDigit(char ch) + { + return ch is >= '0' and <= '9'; + } + + bool IsWhitespaceOrNewline(char ch) + { + return ch is ' ' or '\n' or '\r' or '\t' or '\f'; + } + + char Step(int i = 1) + { + if (source == null) + { + return ' '; + } + + if (pos >= source.Length) + { + return ' '; + } + + char cc = source[pos]; + + if (stepMode == StepModes.CurrentLexeme) + { + currentLexeme.Append(cc); + } + else + { + Buffer.Append(cc); + } + + col += i; + pos += i; + c = cc; + + if (pos >= source.Length) + { + pos = source.Length; + } + + if (cc == '\n') + { + col = 1; + line++; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !IsAtEnd()) + { + if (cc == '\r' && Peek() == '\n') + { + return Step(); + } + } + + return cc; + } + + void SetAddTokenAction(TokenTypes tokenType, Action action) + { + if (AddTokenActions.ContainsKey(tokenType)) + { + AddTokenActions[tokenType] = action; + } + else + { + AddTokenActions.Add(tokenType, action); + } + } + + private int storedPos; + void StorePos() + { + storedPos = pos; + storedCol = col; + storedLine = line; + storedLexeme = currentLexeme.ToString(); + } + + void RestorePos() + { + pos = storedPos; + if (source != null && pos >= source.Length) + { + pos = source.Length - 1; + } + + storedPos = 0; + if (source != null) + { + c = source[pos]; + } + + col = storedCol; + line = storedLine; + DiscardCurrentLexeme(); + currentLexeme.Append(storedLexeme); + } + + string? PeekRange(int from, int length) + { + return source?.Substring(pos + from - 1, length); + } + + char Peek(int i = 1) + { + if (IsAtEnd()) + { + return '\n'; + } + + int peekedPos = pos + i - 1; + + if (peekedPos < 0) + { + pos = 0; + } + + if (source != null && source.Length <= peekedPos) + { + return source[^1]; + } + + return source?[peekedPos] ?? char.MaxValue; + } + + string StepN(int steps) + { + string str = ""; + while (!IsAtEnd() && steps > 0) + { + char chr = Step(); + str += chr; + steps--; + } + + return str; + } + + char GetNextCharNotWhitespace() + { + StorePos(); + char ch = '\0'; + + while (!IsAtEnd()) + { + ch = Step(); + if (Peek() != ' ') + { + break; + } + } + RestorePos(); + + return ch; + } + + string GetBuffer() + { + return Buffer.ToString(); + } + + bool CurrentLexemeIsSelfClosedHtmlTag() + { + return GetCurrentLexeme().EndsWith("/>"); + } + + bool IsSelfClosingHtmlTag(string htmlTag) + { + return IsSelfClosing(htmlTag.ToLowerInvariant().Replace("!", "")); + } + + bool AddTokenSplitRightTrim(TokenTypes lhsType, TokenTypes rhsType) + { + string str = GetCurrentLexeme(); + string lhs = str.TrimEnd(); + + int dif = str.Length - lhs.Length; + bool any = false; + + if (lhs.Length > 0) + { + currentLexeme.Clear(); + currentLexeme.Append(lhs); + any = AddToken(lhsType); + } + + if (dif > 0) + { + string rhs = str.Substring(str.Length - dif); + currentLexeme.Clear(); + currentLexeme.Append(rhs); + bool any2 = AddToken(rhsType); + + if (!any) + { + any = any2; + } + } + + return any; + } + + Token AddAdHocToken(TokenTypes type, string content) + { + Token token = new Token(type, content, 0, 0, 0, 0); + Tokens.Add(token); + + return token; + } + + bool AddToken(TokenTypes type) + { + if (tagParsingMode == HtmlTagParsingModes.TagHelper) + { + return false; + } + + if (currentLexeme.Length == 0) + { + return false; + } + + if (AddTokenActions.ContainsKey(type)) + { + AddTokenActions[type].Invoke(); + AddTokenActions.Remove(type); + } + + Token token = new Token(type, GetCurrentLexeme(), lastCommitedLine + 1, line + 1, lastCommitedPos + 1, pos + 1); + Tokens.Add(token); + DiscardCurrentLexeme(); + + lastCommitedPos = pos; + lastCommitedLine = line; + return true; + } + + void DiscardCurrentLexeme() + { + currentLexeme.Clear(); + } + + void AddBufferToCurrentLexeme() + { + currentLexeme.Append(Buffer); + } + + void FatalIfInBlock(string message) + { + Exception e = new TemplatingEngineException(line, col, pos, message, source ?? ""); + + if (parsingBlock) + { + fatalExceptions.Add(e); + } + else + { + recoveredExceptions.Add(e); + } + } + + bool IsSelfClosing(string tagName) + { + return tagName is "area" + or "base" + or "br" + or "col" + or "embed" + or "hr" + or "img" + or "input" + or "keygen" + or "link" + or "menuitem" + or "meta" + or "param" + or "source" + or "track" + or "wbr" + or "doctype"; + } + + void ClearBuffer(bool start) + { + Buffer.Clear(); + + if (start) + { + storedCol = col; + storedLine = line; + storedC = c; + storedPos = pos; + } + else + { + col = storedCol; + line = storedLine; + c = storedC; + pos = storedPos; + } + } + + void SetStepMode(StepModes mode) + { + stepMode = mode; + } + + bool Throw(string message) + { + throw new TemplatingEngineException(line, col, pos, message, source ?? ""); + } + + void SetParsingControlChars(bool enabled) + { + parsingTransitionCharactersEnabled = enabled; + } + + bool ParsingControlChars() + { + return parsingTransitionCharactersEnabled; + } + + bool StepEol() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (Peek() == '\n' && LastStoredCharMatches('\r')) + { + Step(); + return true; + } + } + + return false; + } + + void DiscardTokensAfter(int n) + { + Tokens = Tokens.GetRange(0, n); + } +} \ No newline at end of file diff --git a/src/WattleScript.Templating/Parser/TagHelper.cs b/src/WattleScript.Templating/Parser/TagHelper.cs new file mode 100644 index 00000000..a4afd31d --- /dev/null +++ b/src/WattleScript.Templating/Parser/TagHelper.cs @@ -0,0 +1,31 @@ +using WattleScript.Interpreter; + +namespace WattleScript.Templating; + +public class TagHelper +{ + public string Name { get; set; } + public string? Template { get; set; } + public byte[]? TemplateBytecode { get; set; } + public string FunctionName { get; set; } + + public TagHelper(string name, string template, byte[] templateBytecode) + { + Name = name; + Template = template; + TemplateBytecode = templateBytecode; + } + + public TagHelper(string name, string template, string functionName) + { + Name = name; + Template = template; + FunctionName = functionName; + } + + public TagHelper(string name, byte[] templateBytecode) + { + Name = name; + TemplateBytecode = templateBytecode; + } +} \ No newline at end of file diff --git a/src/WattleScript.Templating/TemplatingEngine.cs b/src/WattleScript.Templating/TemplatingEngine.cs new file mode 100644 index 00000000..29bc275d --- /dev/null +++ b/src/WattleScript.Templating/TemplatingEngine.cs @@ -0,0 +1,452 @@ +using System.Text; +using System.Text.RegularExpressions; +using WattleScript.Interpreter; +using WattleScript.Interpreter.Execution.VM; + +namespace WattleScript.Templating; + +public class TemplatingEngine +{ + private readonly StringBuilder pooledSb = new StringBuilder(); + private readonly TemplatingEngineOptions options; + internal readonly Script script; + private StringBuilder stdOut = new StringBuilder(); + private StringBuilder stdOutTagHelper = new StringBuilder(); + public readonly List tagHelpers; + internal Dictionary tagHelpersMap = new Dictionary(); + private StringBuilder stdOutTagHelperTmp = new StringBuilder(); + private Parser? parser; + private Table? tagHelpersSharedTbl; + private Dictionary? tagHelperHints; + internal TranspileModes transpileMode = TranspileModes.Run; + + public enum TranspileModes + { + Run, + Dump + } + + internal enum TranspileModesExt + { + None, + DumpRecursive + } + + public TemplatingEngine(TemplatingEngine parent, Table? tbl) + { + options = parent.options; + script = parent.script; + tagHelpers = parent.tagHelpers; + + stdOut = parent.stdOut; + stdOutTagHelper = parent.stdOutTagHelper; + stdOutTagHelperTmp = parent.stdOutTagHelperTmp; + + tagHelpersSharedTbl = tbl; + + SharedSetup(); + } + + public TemplatingEngine(Script script, TemplatingEngineOptions? options = null, List? tagHelpers = null, Dictionary? tagHelperHints = null) + { + options ??= TemplatingEngineOptions.Default; + this.options = options; + this.script = script ?? throw new ArgumentNullException(nameof(script)); + this.tagHelpers = tagHelpers ?? new List(); + this.tagHelperHints = tagHelperHints; + + SharedSetup(); + } + + void SharedSetup() + { + MapTagHelpers(); + SetSpecials(); + } + + void SetSpecials() + { + script.Globals["stdout_line"] = PrintLine; + script.Globals["stdout"] = Print; + script.Globals["render_tag_content"] = RenderTagContent; + } + + void MapTagHelpers() + { + foreach (TagHelper th in tagHelpers) + { + if (tagHelpersMap.ContainsKey(th.Name.ToLowerInvariant())) + { + // [todo] err, tag helper duplicate name + } + + tagHelpersMap.TryAdd(th.Name.ToLowerInvariant(), th); + } + } + + DynValue RenderTagContentDumped(Script s, CallbackArguments args) + { + if (args.Count > 0) + { + DynValue ctx = args[0]; + if (ctx.IsNotNil() && ctx.Type == DataType.Function) + { + ctx.Function.Call(); + } + } + + return DynValue.Void; + } + + DynValue RenderTagContent(Script s, CallbackArguments args) + { + if (args.Count > 0) + { + Table? tbl = null; + + if (parser != null) + { + tbl = script.Globals.Get("__tagData").Table; + parser.tagHelpersSharedTable = tbl; + } + + DynValue arg = args[0]; + string str = arg.String; + string transpiled = new TemplatingEngine(this, tbl).Transpile(str, transpileMode); + + stdOutTagHelperTmp.Clear(); + script.Globals["stdout"] = PrintTaghelperTmp; + script.DoString(transpiled); + + string output = stdOutTagHelperTmp.ToString(); + stdOutTagHelper.Append(output); + + script.Globals["stdout"] = Print; + return DynValue.NewString(output); + } + + return DynValue.Nil; + } + + string EncodeJsString(string s) + { + pooledSb.Clear(); + pooledSb.Append('"'); + foreach (char c in s) + { + switch (c) + { + case '\"': + pooledSb.Append("\\\""); + break; + case '\\': + pooledSb.Append("\\\\"); + break; + case '\b': + pooledSb.Append("\\b"); + break; + case '\f': + pooledSb.Append("\\f"); + break; + case '\n': + pooledSb.Append("\\n"); + break; + case '\r': + pooledSb.Append("\\r"); + break; + case '\t': + pooledSb.Append("\\t"); + break; + default: + int i = c; + if (i is < 32 or > 127) + { + pooledSb.Append($"\\u{i:X04}"); + } + else + { + pooledSb.Append(c); + } + + break; + } + } + + pooledSb.Append('"'); + return pooledSb.ToString(); + } + + List Optimise(List? tokens) + { + if (tokens == null) // if we have no tokens or only one we can't merge + { + return new List(); + } + + if (tokens.Count <= 1) + { + return tokens; + } + + int i = 0; + Token token = tokens[i]; + + while (true) + { + i++; + if (i > tokens.Count - 1) + { + break; + } + + Token nextToken = tokens[i]; + if (token.Type == nextToken.Type) + { + token.Lexeme.Append(nextToken.Lexeme); + token.FromLine = Math.Min(token.FromLine, nextToken.FromLine); + token.ToLine = Math.Max(token.ToLine, nextToken.ToLine); + token.StartCol = Math.Min(token.StartCol, nextToken.StartCol); + token.EndCol = Math.Max(token.EndCol, nextToken.EndCol); + + tokens.RemoveAt(i); + i--; + continue; + } + + // move to next token + token = tokens[i]; + } + + return tokens; + } + + public string Debug(string code) + { + if (string.IsNullOrWhiteSpace(code)) + { + return ""; + } + + parser = new Parser(this, script, tagHelpersSharedTbl, null); + List tokens = parser.Parse(code, transpileMode, ""); + pooledSb.Clear(); + + if (options.Optimise) + { + tokens = Optimise(tokens); + } + + foreach (Token tkn in tokens) + { + pooledSb.AppendLine(tkn.ToString()); + } + + string finalText = pooledSb.ToString(); + return finalText; + } + + internal string TranspileRecursive(string code, Dictionary loadedTagHelpers) + { + Parser locParser = new Parser(this, script, tagHelpersSharedTbl, tagHelperHints); + List tokens = locParser.Parse(code, TranspileModes.Dump, "", TranspileModesExt.DumpRecursive, loadedTagHelpers); + + string str = Transform(tokens); + return str; + } + + public string Transpile(string code, TranspileModes mode = TranspileModes.Run, string friendlyName = "") + { + if (string.IsNullOrWhiteSpace(code)) + { + return ""; + } + + parser = new Parser(this, script, tagHelpersSharedTbl, tagHelperHints); + List tokens = parser.Parse(code, mode, friendlyName); + + string str = Transform(tokens); + return str; + } + + internal string Transform(List tokens) + { + StringBuilder sb = new StringBuilder(); + bool firstClientPending = true; + + if (options.Optimise) + { + tokens = Optimise(tokens); + } + + foreach (Token tkn in tokens) + { + if (options.RunMode == TemplatingEngineOptions.RunModes.Debug) + { + sb.AppendLine($"#line {tkn.FromLine}, {tkn.StartCol}"); + } + + switch (tkn.Type) + { + case TokenTypes.Text: + { + string lexeme = tkn.Lexeme.ToString(); + if (firstClientPending) + { + lexeme = lexeme.TrimStart(); + firstClientPending = false; + } + + sb.AppendLine($"stdout({EncodeJsString(lexeme)})"); + break; + } + case TokenTypes.BlockExpr: + string str = tkn.Lexeme.ToString(); + if (string.IsNullOrWhiteSpace(str)) + { + continue; + } + + sb.AppendLine(str); + break; + case TokenTypes.ImplicitExpr: + case TokenTypes.ExplicitExpr: + sb.AppendLine($"stdout({tkn.Lexeme})"); + break; + case TokenTypes.Comment: + sb.AppendLine($"/*{tkn.Lexeme}*/"); + break; + } + } + + string finalText = sb.ToString(); + return finalText; + } + + DynValue ParseTagHelperAsFunc(string code, Script sc) + { + string transpiledTemplate = Transpile(code, transpileMode, "tagHelperDefinition"); + DynValue dv = script.LoadString(transpiledTemplate); + + foreach (FunctionProto? fn in dv.Function.Function.Functions) + { + var annot = fn.Annotations?.FirstOrDefault(x => x.Name == "tagHelper"); + + if (annot == null) + { + continue; + } + + string snip = fn.GetSourceFragment(transpiledTemplate); + string[] snipLines = snip.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); + List outLines = new List(); + foreach (string snipLine in snipLines) + { + if (!snipLine.StartsWith("#line")) + { + outLines.Add(snipLine); + } + } + + snip = string.Join("\n", outLines); // get rid of generated #line + + string proxyName = $"__tagHelper_{Guid.NewGuid().ToString().Replace("-", "")}"; + + tagHelpers.Add(new TagHelper(annot.Value.Table.Values.First().String, snip, fn.Name)); + } + + return dv; + } + + public void ParseTagHelper(string code, Script sc) + { + stdOut.Clear(); + ParseTagHelperAsFunc(code, sc); + } + + public async Task> GetAfterRenderHints() + { + Dictionary dict = new Dictionary(); + + if (parser != null) + { + if (parser.pendingTemplateParts.Count > 0) + { + foreach (KeyValuePair pair in parser.pendingTemplateParts) + { + await using MemoryStream ms = new MemoryStream(); + script.Dump(pair.Value, ms); + byte[] arr = ms.ToArray(); + + dict.Add(pair.Key, arr); + } + } + } + + return dict; + } + + public byte[] Dump(string code, Table? globalContext = null, string? friendlyCodeName = null, bool writeSourceRefs = true) + { + transpileMode = TranspileModes.Dump; + stdOut.Clear(); + + string transpiledTemplate = Transpile(code, transpileMode); + + DynValue dv = script.LoadString(transpiledTemplate, globalContext, friendlyCodeName); + + return script.Dump(dv, writeSourceRefs); + } + + public async Task Render(byte[] bytecode, Table? globalContext = null, string? friendlyCodeName = null) + { + transpileMode = TranspileModes.Run; + stdOut.Clear(); + + script.Globals["render_tag_content"] = RenderTagContentDumped; + + using MemoryStream ms = new MemoryStream(bytecode); + await script.DoStreamAsync(ms, globalContext, friendlyCodeName); + string htmlText = stdOut.ToString(); + + return new RenderResult() {Output = htmlText, Transpiled = ""}; + } + + public async Task Render(string code, Table? globalContext = null, string? friendlyCodeName = null) + { + stdOut.Clear(); + + string transpiledTemplate = Transpile(code); + await script.DoStringAsync(transpiledTemplate, globalContext, friendlyCodeName); + string htmlText = stdOut.ToString(); + + return new RenderResult() {Output = htmlText, Transpiled = transpiledTemplate}; + } + + private void PrintLine(Script script, CallbackArguments args) + { + stdOut.AppendLine(args[0].CastToString()); + } + + public void Print(Script script, CallbackArguments args) + { + stdOut.Append(args[0].CastToString()); + } + + public void PrintTaghelper(Script script, CallbackArguments args) + { + string str = args[0].CastToString(); + stdOutTagHelper.Append(str); + } + + public void PrintTaghelperTmp(Script script, CallbackArguments args) + { + string str = args[0].CastToString(); + stdOutTagHelperTmp.Append(str); + } + + public class RenderResult + { + public string Output { get; init; } + public string Transpiled { get; init; } + } +} \ No newline at end of file diff --git a/src/WattleScript.Templating/TemplatingEngineException.cs b/src/WattleScript.Templating/TemplatingEngineException.cs new file mode 100644 index 00000000..3ff2b34a --- /dev/null +++ b/src/WattleScript.Templating/TemplatingEngineException.cs @@ -0,0 +1,55 @@ +using System.Text; + +namespace WattleScript.Templating; + +public sealed class TemplatingEngineException : Exception +{ + private int Line { get; init; } + private int Col { get; init; } + private string Snippet { get; init; } + private string Decor { get; init; } + + public TemplatingEngineException(int line, int col, int pos, string message, string rawSource) : base(message) + { + Tuple snippet = rawSource.Snippet(pos, 40); // show full text for now, might be more useful + + Line = line; + Col = col; + Snippet = rawSource; + + int decorCol = col; + + int insertPos = Snippet.IndexOf('\n', pos); + if (insertPos > -1 && Snippet.Length > insertPos + 1) + { + if (Snippet[insertPos + 1] == '\r') + { + insertPos++; + } + } + if (insertPos == -1) + { + insertPos = Snippet.Length; + decorCol = 0; + } + + if (pos >= rawSource.Length - 1) + { + decorCol = 0; + insertPos = Snippet.Length; + } + + StringBuilder decorBuilder = new StringBuilder(); + for (int i = 0; i < decorCol - 1; i++) + { + decorBuilder.Append('-'); + } + + decorBuilder.Append('^'); + Decor = decorBuilder.ToString(); + + Snippet = Snippet.Insert(insertPos, $"\n{Decor}"); + } + + public string FormatedMessage => $"{Snippet}\nLine {Line}, col {Col}: {Message}"; +} \ No newline at end of file diff --git a/src/WattleScript.Templating/TemplatingEngineOptions.cs b/src/WattleScript.Templating/TemplatingEngineOptions.cs new file mode 100644 index 00000000..fd02a8cf --- /dev/null +++ b/src/WattleScript.Templating/TemplatingEngineOptions.cs @@ -0,0 +1,24 @@ +namespace WattleScript.Templating; + +public class TemplatingEngineOptions +{ + public enum RunModes + { + Debug, + Release + } + + public static readonly TemplatingEngineOptions Default = new TemplatingEngineOptions() {Optimise = true}; + + /// + /// True = a slightly longer parsing, a slightly slower execution + /// False = a slightly faster parsing, a slightly faster execution + /// + public bool Optimise { get; set; } + + /// + /// Debug = emit #line, use string sources where possible + /// Release = don't emit #line, use byte[] sources where possible + /// + public RunModes RunMode { get; set; } +} \ No newline at end of file diff --git a/src/WattleScript.Templating/Token.cs b/src/WattleScript.Templating/Token.cs new file mode 100644 index 00000000..e8ab2fe3 --- /dev/null +++ b/src/WattleScript.Templating/Token.cs @@ -0,0 +1,46 @@ +using System.ComponentModel; +using System.Text; + +namespace WattleScript.Templating; + +internal enum TokenTypes +{ + [Description("BLOCK")] + BlockExpr, + [Description("EXPLICIT")] + ExplicitExpr, + [Description("IMPLICIT")] + ImplicitExpr, + [Description("TEXT")] + Text, + [Description("COMMENT")] + Comment, + [Description("EOF")] + Eof, + Length +} + +internal class Token +{ + public TokenTypes Type { get; set; } + public StringBuilder Lexeme { get; set; } + public int FromLine { get; set; } + public int ToLine { get; set; } + public int StartCol { get; set; } + public int EndCol { get; set; } + + public Token(TokenTypes type, string lexeme, int fromLine, int toLine, int startCol, int endCol) + { + Type = type; + Lexeme = new StringBuilder(lexeme); + FromLine = fromLine; + ToLine = toLine; + StartCol = startCol; + EndCol = endCol; + } + + public override string ToString() + { + return $"{Type.ToDescriptionString()} [ln {FromLine}-{ToLine}, col {StartCol}-{EndCol}] - {Lexeme}"; + } +} \ No newline at end of file diff --git a/src/WattleScript.Templating/WattleScript.Templating.csproj b/src/WattleScript.Templating/WattleScript.Templating.csproj new file mode 100644 index 00000000..16a2a1f5 --- /dev/null +++ b/src/WattleScript.Templating/WattleScript.Templating.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/src/WattleScript.Tests/EndToEnd/CLike/SyntaxCLike/Misc/1-call-chain.lua b/src/WattleScript.Tests/EndToEnd/CLike/SyntaxCLike/Misc/1-call-chain.lua new file mode 100644 index 00000000..7b342ce2 --- /dev/null +++ b/src/WattleScript.Tests/EndToEnd/CLike/SyntaxCLike/Misc/1-call-chain.lua @@ -0,0 +1,9 @@ +acc = { + myTbl: [10] +} + +fn = () => { +return [ [acc] ] +} + +print(fn()[0][0].myTbl[0]); \ No newline at end of file diff --git a/src/WattleScript.Tests/EndToEnd/CLike/SyntaxCLike/Misc/1-call-chain.txt b/src/WattleScript.Tests/EndToEnd/CLike/SyntaxCLike/Misc/1-call-chain.txt new file mode 100644 index 00000000..9a037142 --- /dev/null +++ b/src/WattleScript.Tests/EndToEnd/CLike/SyntaxCLike/Misc/1-call-chain.txt @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/src/WattleScript.Tests/EndToEnd/CLike/SyntaxCLike/Misc/2-length.lua b/src/WattleScript.Tests/EndToEnd/CLike/SyntaxCLike/Misc/2-length.lua new file mode 100644 index 00000000..43dc863e --- /dev/null +++ b/src/WattleScript.Tests/EndToEnd/CLike/SyntaxCLike/Misc/2-length.lua @@ -0,0 +1 @@ +print([1, 2, 3].length); \ No newline at end of file diff --git a/src/WattleScript.Tests/EndToEnd/CLike/SyntaxCLike/Misc/2-length.txt b/src/WattleScript.Tests/EndToEnd/CLike/SyntaxCLike/Misc/2-length.txt new file mode 100644 index 00000000..e440e5c8 --- /dev/null +++ b/src/WattleScript.Tests/EndToEnd/CLike/SyntaxCLike/Misc/2-length.txt @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/TemplatingTestsRunner.cs b/src/WattleScript.Tests/Templating/TemplatingTestsRunner.cs new file mode 100644 index 00000000..35be9465 --- /dev/null +++ b/src/WattleScript.Tests/Templating/TemplatingTestsRunner.cs @@ -0,0 +1,323 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using NUnit.Framework; +using WattleScript.Interpreter.Loaders; +using WattleScript.Templating; + +namespace WattleScript.Interpreter.Tests.Templating; + +class TemplatingTestsScriptLoader : ScriptLoaderBase +{ + public override bool ScriptFileExists(string name) + { + return true; + } + + public override object LoadFile(string file, Table globalContext) + { + return "fn = () => 'Hello world'"; + } + + protected override string ResolveModuleName(string modname, string[] paths) + { + return modname; + } +} + +[TestFixture] +[Parallelizable(ParallelScope.All)] +public class TemplatingTestsRunner +{ + private const bool COMPILE_TAG_HELPERS = true; + private const bool RUN_SLOW_TESTS = false; + + private const string ROOT_FOLDER = "Templating/Tests"; + private static Filter filter = Filter.Tests; + private List tagHelpers = new List(); + + public static string Snippet(string str, int pivot, int n) + { + int expectedStart = pivot - n; + int realStart = Math.Max(0, str.Length > expectedStart ? expectedStart : str.Length); + int expectedLen = 2 * n; + int realLen = Math.Max(str.Length - realStart > expectedLen ? expectedLen : str.Length - realStart, 0); + + return str.Substring(realStart, realLen); + } + + enum Filter + { + Tests, + TagDefinitions + } + + static int strDifIndex(string s1, string s2) + { + int index = 0; + int min = Math.Min(s1.Length, s2.Length); + + while (index < min && s1[index] == s2[index]) + { + index++; + } + + return index == min && s1.Length == s2.Length ? -1 : index; + } + + static string[] GetTestCases() + { + string[] files = Directory.GetFiles(ROOT_FOLDER, "*.wthtml*", SearchOption.AllDirectories); + + if (filter == Filter.TagDefinitions) + { + return files.Where(x => x.Contains("TagDefinitions")).ToArray(); + } + + if (filter == Filter.Tests) + { + return files.Where(x => !x.Contains("TagDefinitions")).ToArray(); + } + + return Array.Empty(); + } + + [WattleScriptUserData] + class HtmlModule + { + public static DynValue Encode(ScriptExecutionContext context, CallbackArguments args) + { + return DynValue.NewString(HttpUtility.HtmlEncode(args[0].String)); + } + + public static DynValue Raw(ScriptExecutionContext context, CallbackArguments args) + { + return DynValue.NewString(args[0].String); + } + } + + [OneTimeSetUp] + public async Task Init() + { + UserData.RegisterAssembly(Assembly.GetAssembly(typeof(HtmlModule))); + + if (!COMPILE_TAG_HELPERS) + { + return; + } + + filter = Filter.TagDefinitions; + foreach (string path in GetTestCases()) + { + string code = await File.ReadAllTextAsync(path); + + Script script = new Script(CoreModules.Preset_SoftSandboxWattle | CoreModules.LoadMethods); + script.Options.IndexTablesFrom = 0; + script.Options.AnnotationPolicy = new CustomPolicy(AnnotationValueParsingPolicy.ForceTable); + script.Options.Syntax = ScriptSyntax.Wattle; + script.Options.Directives.Add("using"); + + HtmlModule htmlModule = new HtmlModule(); + script.Globals["Html"] = htmlModule; + + TemplatingEngine tmp = new TemplatingEngine(script); + + try + { + tmp.ParseTagHelper(code, script); + tagHelpers.AddRange(tmp.tagHelpers); + } + catch (Exception e) + { + Assert.Fail($"Error parsing tag helper definition\nPath: {path}\nMessage: {e.Message}\nStacktrace: {e.StackTrace}"); + } + } + + filter = Filter.Tests; + } + + [Test, TestCaseSource(nameof(GetTestCases))] + public async Task RunThrowErros(string path) + { + await RunCore(path); + } + + public async Task RunCore(string path, bool reportErrors = false, bool runningFromDump = false) + { + if (path.Contains("TagHintsGenerated")) + { + return; + } + + string outputPath = path.Replace(".wthtml", ".html"); + + if (!File.Exists(outputPath)) + { + Assert.Inconclusive($"Missing output file for test {path}"); + return; + } + + string testName = Path.GetFileName(path); + string currentDir = Directory.GetParent(Environment.CurrentDirectory)?.Parent?.Parent?.FullName; + + string code = await File.ReadAllTextAsync(path); + string output = await File.ReadAllTextAsync(outputPath); + + Script script = new Script(CoreModules.Preset_SoftSandboxWattle | CoreModules.LoadMethods); + script.Options.IndexTablesFrom = 0; + script.Options.AnnotationPolicy = new CustomPolicy(AnnotationValueParsingPolicy.ForceTable); + script.Options.Syntax = ScriptSyntax.Wattle; + script.Options.Directives.Add("using"); + script.Options.ScriptLoader = new TemplatingTestsScriptLoader(); + + HtmlModule htmlModule = new HtmlModule(); + script.Globals["Html"] = htmlModule; + + Dictionary hintsDict = new Dictionary(); + /*if (runningFromDump) + { + string[] hints = Directory.GetFiles($"{currentDir}\\Templating\\Tests\\TagHelpers\\TagHintsGenerated\\{testName}"); + foreach (string hint in hints) + { + if (!hint.Contains(".txt")) + { + continue; + } + + string hintText = await File.ReadAllTextAsync(hint); + byte[] hintDump = await File.ReadAllBytesAsync(hint.Replace(".txt", ".bin")); + + if (!hintsDict.ContainsKey(hintText)) + { + hintsDict.Add(hintText, hintDump); + } + } + }*/ + + TemplatingEngine tmp = new TemplatingEngine(script, null, tagHelpers, hintsDict); + TemplatingEngine.RenderResult rr = null; + + if (path.Contains("slow")) + { + if (!RUN_SLOW_TESTS) + { + Assert.Pass($"Test {path} skipped due to being marked as 'slow' and RUN_SLOW_TESTS set to 'false'"); + return; + } + } + + if (path.Contains("flaky")) + { + Assert.Inconclusive($"Test {path} marked as flaky"); + return; + } + + if (path.Contains("SyntaxCLike")) + { + script.Options.Syntax = ScriptSyntax.Wattle; + } + + if (reportErrors) + { + script.Options.ParserErrorMode = ScriptOptions.ParserErrorModes.Report; + await tmp.Render(code); + return; + } + + try + { + if (!runningFromDump) + { + rr = await tmp.Render(code); + } + else + { + byte[] dumpedBc = tmp.Dump(code); + rr = await tmp.Render(dumpedBc); + + if (!string.Equals(output, rr.Output)) + { + int difIndex = strDifIndex(output, rr.Output); + string diffSnippet = Snippet(rr.Output, difIndex, 50); + string expectedSnippet = Snippet(output, difIndex, 50); + + Assert.Fail($"Test failed from dumped BC, ok when running from string. Output and expected HTML are not equal.\nFirst difference at index: {difIndex}\nOutput near diff: {diffSnippet}\nExpected near diff: {expectedSnippet}\n---------------------- Expected ----------------------\n{output}\n---------------------- But was------------------------\n{rr.Output}\n------------------------------------------------------\n"); + } + } + + if (string.Equals(output, rr.Output)) + { + /*if (hints.Any() && !runningFromDump) + { + if (!string.IsNullOrWhiteSpace(currentDir)) + { + Directory.CreateDirectory( $"{currentDir}\\Templating\\Tests\\TagHelpers\\TagHintsGenerated\\{testName}"); + int i = 0; + foreach (KeyValuePair hint in hints) + { + await File.WriteAllTextAsync($"{currentDir}\\Templating\\Tests\\TagHelpers\\TagHintsGenerated\\{testName}\\hint{i}.txt", hint.Key); + await File.WriteAllBytesAsync($"{currentDir}\\Templating\\Tests\\TagHelpers\\TagHintsGenerated\\{testName}\\hint{i}.bin", hint.Value); + + i++; + } + } + + await RunCore(path, false, true); + }*/ + + if (!runningFromDump) + { + await RunCore(path, false, true); + } + + Assert.Pass(); + } + else + { + int difIndex = strDifIndex(output, rr.Output); + string diffSnippet = Snippet(rr.Output, difIndex, 50); + string expectedSnippet = Snippet(output, difIndex, 50); + + Assert.Fail($"Test failed. Output and expected HTML are not equal.\nFirst difference at index: {difIndex}\nOutput near diff: {diffSnippet}\nExpected near diff: {expectedSnippet}\n---------------------- Expected ----------------------\n{output}\n---------------------- But was------------------------\n{rr.Output}\n------------------------------------------------------\n"); + } + + if (path.ToLowerInvariant().Contains("invalid")) + { + Assert.Fail("Expected to crash but 'passed'"); + } + + } + catch (Exception e) + { + if (e is SuccessException) + { + return; + } + + if (path.ToLowerInvariant().Contains("invalid")) + { + if (e is TemplatingEngineException tee) + { + Assert.Pass($"Crashed as expected:\n{tee.FormatedMessage}"); + return; + } + + Assert.Pass($"Crashed as expected: {e.Message}"); + return; + } + + if (e is AssertionException ae) + { + Assert.Fail($"---------------------- Parsed template ----------------------\n{rr?.Transpiled ?? ""}\n---------------------- Stacktrace ----------------------\n{ae.StackTrace}\n"); + return; + } + + Assert.Fail($"Test {path} did not pass.\nMessage: {e.Message}\n{e.StackTrace}"); + } + } +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/1-simple.html b/src/WattleScript.Tests/Templating/Tests/CodeBlock/1-simple.html new file mode 100644 index 00000000..d754db6f --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/1-simple.html @@ -0,0 +1,2 @@ +
test
+ 103 \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/1-simple.wthtml b/src/WattleScript.Tests/Templating/Tests/CodeBlock/1-simple.wthtml new file mode 100644 index 00000000..47bf67f5 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/1-simple.wthtml @@ -0,0 +1,6 @@ +
test
+ @{ t = 100 + t++ + t++ + t++ + }@t \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/2-if.html b/src/WattleScript.Tests/Templating/Tests/CodeBlock/2-if.html new file mode 100644 index 00000000..1875b4c2 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/2-if.html @@ -0,0 +1 @@ +
1000
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/2-if.wthtml b/src/WattleScript.Tests/Templating/Tests/CodeBlock/2-if.wthtml new file mode 100644 index 00000000..c53a4a1d --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/2-if.wthtml @@ -0,0 +1,8 @@ +@{ + x = 0 + if (2 > 1) { + x = 1000 + } + +} +
@x
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/3-string.html b/src/WattleScript.Tests/Templating/Tests/CodeBlock/3-string.html new file mode 100644 index 00000000..1875b4c2 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/3-string.html @@ -0,0 +1 @@ +
1000
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/3-string.wthtml b/src/WattleScript.Tests/Templating/Tests/CodeBlock/3-string.wthtml new file mode 100644 index 00000000..599f7adb --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/3-string.wthtml @@ -0,0 +1,8 @@ +@{ + x = 0 z = '}' + if (2 > 1) { + x = 1000 + } + +} +
@x
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/4-comment.html b/src/WattleScript.Tests/Templating/Tests/CodeBlock/4-comment.html new file mode 100644 index 00000000..1875b4c2 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/4-comment.html @@ -0,0 +1 @@ +
1000
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/4-comment.wthtml b/src/WattleScript.Tests/Templating/Tests/CodeBlock/4-comment.wthtml new file mode 100644 index 00000000..adac11da --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/4-comment.wthtml @@ -0,0 +1,8 @@ +@{ + x = 0 // } + if (2 > 1) { + x = 1000 + } + +} +
@x
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/5-mix.html b/src/WattleScript.Tests/Templating/Tests/CodeBlock/5-mix.html new file mode 100644 index 00000000..002f0d9d --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/5-mix.html @@ -0,0 +1 @@ +
0
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/5-mix.wthtml b/src/WattleScript.Tests/Templating/Tests/CodeBlock/5-mix.wthtml new file mode 100644 index 00000000..24ab1b03 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/5-mix.wthtml @@ -0,0 +1,8 @@ +@{ + x = 2 y = '\'}\'"` /*}*/ //}' /*}*/ /* } */ x = 0 // } + if (x > 1) { + x = 1000 + } + +} +
@x
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/6-mix2-invalid.html b/src/WattleScript.Tests/Templating/Tests/CodeBlock/6-mix2-invalid.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/6-mix2-invalid.wthtml b/src/WattleScript.Tests/Templating/Tests/CodeBlock/6-mix2-invalid.wthtml new file mode 100644 index 00000000..df73c1d4 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/6-mix2-invalid.wthtml @@ -0,0 +1,8 @@ +@{ + x = 2 /* + if (x > 1) { + x = 1000 + } + +} +
@x
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/7-mix3-invalid.html b/src/WattleScript.Tests/Templating/Tests/CodeBlock/7-mix3-invalid.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/7-mix3-invalid.wthtml b/src/WattleScript.Tests/Templating/Tests/CodeBlock/7-mix3-invalid.wthtml new file mode 100644 index 00000000..bc94d77b --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/7-mix3-invalid.wthtml @@ -0,0 +1,8 @@ +@{ + x = 2 y = " + if (x > 1) { + x = 1000 + } + +} +
@x
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/8-mix4-invalid.html b/src/WattleScript.Tests/Templating/Tests/CodeBlock/8-mix4-invalid.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/CodeBlock/8-mix4-invalid.wthtml b/src/WattleScript.Tests/Templating/Tests/CodeBlock/8-mix4-invalid.wthtml new file mode 100644 index 00000000..b7004a1c --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/CodeBlock/8-mix4-invalid.wthtml @@ -0,0 +1,2 @@ +@{ // } +
@x
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Comments/1-simple.html b/src/WattleScript.Tests/Templating/Tests/Comments/1-simple.html new file mode 100644 index 00000000..281c6866 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Comments/1-simple.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Comments/1-simple.wthtml b/src/WattleScript.Tests/Templating/Tests/Comments/1-simple.wthtml new file mode 100644 index 00000000..ca570165 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Comments/1-simple.wthtml @@ -0,0 +1,2 @@ +@* comment *@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Escape/1-simple.html b/src/WattleScript.Tests/Templating/Tests/Escape/1-simple.html new file mode 100644 index 00000000..b516b2c4 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Escape/1-simple.html @@ -0,0 +1 @@ +@ \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Escape/1-simple.wthtml b/src/WattleScript.Tests/Templating/Tests/Escape/1-simple.wthtml new file mode 100644 index 00000000..fffa12f0 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Escape/1-simple.wthtml @@ -0,0 +1 @@ +@@ \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Escape/2-escape-with-text.html b/src/WattleScript.Tests/Templating/Tests/Escape/2-escape-with-text.html new file mode 100644 index 00000000..f773d513 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Escape/2-escape-with-text.html @@ -0,0 +1 @@ +@text \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Escape/2-escape-with-text.wthtml b/src/WattleScript.Tests/Templating/Tests/Escape/2-escape-with-text.wthtml new file mode 100644 index 00000000..fe983c8c --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Escape/2-escape-with-text.wthtml @@ -0,0 +1 @@ +@@text \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/1-simple.html b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/1-simple.html new file mode 100644 index 00000000..b6468798 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/1-simple.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/1-simple.wthtml b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/1-simple.wthtml new file mode 100644 index 00000000..199897cc --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/1-simple.wthtml @@ -0,0 +1,4 @@ +@{ + x = 'myAttr' +} +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/2-attr.html b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/2-attr.html new file mode 100644 index 00000000..a696f34e --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/2-attr.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/2-attr.wthtml b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/2-attr.wthtml new file mode 100644 index 00000000..4facd4d8 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/2-attr.wthtml @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/3-attr-2.html b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/3-attr-2.html new file mode 100644 index 00000000..c449f96b --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/3-attr-2.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/3-attr-2.wthtml b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/3-attr-2.wthtml new file mode 100644 index 00000000..ed1be671 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/3-attr-2.wthtml @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/4-escape.html b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/4-escape.html new file mode 100644 index 00000000..ef91ce1b --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/4-escape.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/4-escape.wthtml b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/4-escape.wthtml new file mode 100644 index 00000000..436864b9 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/4-escape.wthtml @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/5-escape-comment.html b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/5-escape-comment.html new file mode 100644 index 00000000..ef91ce1b --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/5-escape-comment.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/5-escape-comment.wthtml b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/5-escape-comment.wthtml new file mode 100644 index 00000000..88b54401 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/5-escape-comment.wthtml @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/6-escape-comment-mixed.html b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/6-escape-comment-mixed.html new file mode 100644 index 00000000..ef91ce1b --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/6-escape-comment-mixed.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/6-escape-comment-mixed.wthtml b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/6-escape-comment-mixed.wthtml new file mode 100644 index 00000000..da6f031e --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/6-escape-comment-mixed.wthtml @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/7-explicit-escape.html b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/7-explicit-escape.html new file mode 100644 index 00000000..d0be2593 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/7-explicit-escape.html @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/7-explicit-escape.wthtml b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/7-explicit-escape.wthtml new file mode 100644 index 00000000..109b394a --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ExplicitExpr/7-explicit-escape.wthtml @@ -0,0 +1,7 @@ +@! { + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/1-w3s.html b/src/WattleScript.Tests/Templating/Tests/Html/1-w3s.html new file mode 100644 index 00000000..149d33d2 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/1-w3s.html @@ -0,0 +1,1324 @@ + + + + HTML Basic + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + Tutorials + References + Exercises + Videos + Pro NEW + + Menu + +
+
+ + +
+ + +
+ + + + +
+
+
+ + + HTML + CSS + JAVASCRIPT + SQL + PYTHON + PHP + BOOTSTRAP + HOW TO + W3.CSS + JAVA + JQUERY + C + C++ + C# + R + React + + + + + + + + +
+ +
+ +
+ +
+ + + + + + + + +
+
+ + + + + + +
+
+
+ +

HTML Tutorial

+ HTML HOME + HTML Introduction + HTML Editors + HTML Basic + HTML Elements + HTML Attributes + HTML Headings + HTML Paragraphs + HTML Styles + HTML Formatting + HTML Quotations + HTML Comments + HTML Colors +
+ Colors + RGB + HEX + HSL +
+ HTML CSS + HTML Links + + HTML Images + + HTML Favicon + HTML Tables + + + + + HTML Lists + + HTML Block & Inline + HTML Classes + HTML Id + HTML Iframes + HTML JavaScript + HTML File Paths + HTML Head + HTML Layout + HTML Responsive + HTML Computercode + HTML Semantics + HTML Style Guide + HTML Entities + HTML Symbols + HTML Emojis + HTML Charset + HTML URL Encode + HTML vs. XHTML +
+

HTML Forms

+ HTML Forms + HTML Form Attributes + HTML Form Elements + HTML Input Types + HTML Input Attributes + HTML Input Form Attributes +
+

HTML Graphics

+ HTML Canvas + HTML SVG +
+

HTML Media

+ HTML Media + HTML Video + HTML Audio + HTML Plug-ins + HTML YouTube +
+

HTML APIs

+ HTML Geolocation + HTML Drag/Drop + HTML Web Storage + HTML Web Workers + HTML SSE +
+

HTML Examples

+ HTML Examples + HTML Quiz + HTML Exercises + HTML Certificate + HTML Summary + HTML Accessibility +
+

HTML References

+ HTML Tag List + HTML Attributes + HTML Global Attributes + HTML Browser Support + HTML Events + HTML Colors + HTML Canvas + HTML Audio/Video + HTML Doctypes + HTML Character Sets + HTML URL Encode + HTML Lang Codes + HTTP Messages + HTTP Methods + PX to EM Converter + Keyboard Shortcuts +

+
+
+
+
+
+
+
+ + + +
+ + +
+

HTML Basic Examples

+ +
+

In this chapter we will show some basic HTML examples.

+

Don't worry if we use tags you have not learned about yet.

+
+ +

HTML Documents

+

All HTML documents must start with a document type declaration: <!DOCTYPE html>.

+

The HTML document itself begins with <html> and ends with </html>.

+

The visible part of the HTML document is between <body> and </body>.

+
+

Example

+
+ <!DOCTYPE html>
<html>
<body>

<h1>My First Heading</h1>
<p>My first paragraph.</p>

</body>
</html>
+ Try it Yourself » +
+
+ +

The <!DOCTYPE> Declaration

+

The <!DOCTYPE> declaration represents the document type, and helps browsers to display web pages correctly.

+

It must only appear once, at the top of the page (before any HTML tags).

+

The <!DOCTYPE> declaration is not case sensitive.

+

The <!DOCTYPE> declaration for HTML5 is:

+
+
+ <!DOCTYPE html>
+
+
+ +

HTML Headings

+

HTML headings are defined with the <h1> to <h6> tags.

+

<h1> defines the most important heading. <h6> defines the least important + heading: 

+
+

Example

+
+ <h1>This is heading 1</h1>
+ <h2>This is heading 2</h2>
+ <h3>This is heading 3</h3> +
+ Try it Yourself » +
+ +
+
+ + + +
+ +
+
+ +

HTML Paragraphs

+

HTML paragraphs are defined with the <p> tag:

+
+

Example

+
+ <p>This is a paragraph.</p>
+ <p>This is another paragraph.</p> +
+ Try it Yourself » +
+
+ +

HTML Links

+

HTML links are defined with the <a> tag:

+
+

Example

+
+ <a href="https://www.w3schools.com">This is a link</a> +
+ Try it Yourself » +
+

The link's destination is specified in the href attribute. 

+

Attributes are used to provide additional information about HTML elements.

+

You will learn more about attributes in a later chapter.

+
+ +

HTML Images

+

HTML images are defined with the <img> tag.

+

The source file (src), alternative text (alt), + width, and height are provided as attributes:

+
+

Example

+
+ <img src="w3schools.jpg" alt="W3Schools.com" width="104" height="142"> +
+ Try it Yourself » +
+
+ +

How to View HTML Source?

+

Have you ever seen a Web page and wondered "Hey! How did they do that?"

+

View HTML Source Code:

+

Right-click in an HTML page and select "View Page Source" (in + Chrome) or "View Source" (in Edge), or similar in other browsers. This will open a window + containing the HTML source code of the page.

+

Inspect an HTML Element:

+

Right-click on an element (or a blank area), and choose "Inspect" or + "Inspect Element" to see what elements are made up of (you will see both + the HTML and the CSS). You can also edit the HTML or CSS on-the-fly in the + Elements or Styles panel that opens.

+ +
+ +
+
+ +
+ +
+ + +
+ + + + + + + diff --git a/src/WattleScript.Tests/Templating/Tests/Html/1-w3s.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/1-w3s.wthtml new file mode 100644 index 00000000..702a878d --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/1-w3s.wthtml @@ -0,0 +1,1324 @@ + + + + HTML Basic + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + Tutorials + References + Exercises + Videos + Pro NEW + + Menu + +
+
+ + +
+ + +
+ + + + +
+
+
+ + + HTML + CSS + JAVASCRIPT + SQL + PYTHON + PHP + BOOTSTRAP + HOW TO + W3.CSS + JAVA + JQUERY + C + C++ + C# + R + React + + + + + + + + +
+ +
+ +
+ +
+ + + + + + + + +
+
+ + + + + + +
+
+
+ +

HTML Tutorial

+ HTML HOME + HTML Introduction + HTML Editors + HTML Basic + HTML Elements + HTML Attributes + HTML Headings + HTML Paragraphs + HTML Styles + HTML Formatting + HTML Quotations + HTML Comments + HTML Colors +
+ Colors + RGB + HEX + HSL +
+ HTML CSS + HTML Links + + HTML Images + + HTML Favicon + HTML Tables + + + + + HTML Lists + + HTML Block & Inline + HTML Classes + HTML Id + HTML Iframes + HTML JavaScript + HTML File Paths + HTML Head + HTML Layout + HTML Responsive + HTML Computercode + HTML Semantics + HTML Style Guide + HTML Entities + HTML Symbols + HTML Emojis + HTML Charset + HTML URL Encode + HTML vs. XHTML +
+

HTML Forms

+ HTML Forms + HTML Form Attributes + HTML Form Elements + HTML Input Types + HTML Input Attributes + HTML Input Form Attributes +
+

HTML Graphics

+ HTML Canvas + HTML SVG +
+

HTML Media

+ HTML Media + HTML Video + HTML Audio + HTML Plug-ins + HTML YouTube +
+

HTML APIs

+ HTML Geolocation + HTML Drag/Drop + HTML Web Storage + HTML Web Workers + HTML SSE +
+

HTML Examples

+ HTML Examples + HTML Quiz + HTML Exercises + HTML Certificate + HTML Summary + HTML Accessibility +
+

HTML References

+ HTML Tag List + HTML Attributes + HTML Global Attributes + HTML Browser Support + HTML Events + HTML Colors + HTML Canvas + HTML Audio/Video + HTML Doctypes + HTML Character Sets + HTML URL Encode + HTML Lang Codes + HTTP Messages + HTTP Methods + PX to EM Converter + Keyboard Shortcuts +

+
+
+
+
+
+
+
+ + + +
+ + +
+

HTML Basic Examples

+ +
+

In this chapter we will show some basic HTML examples.

+

Don't worry if we use tags you have not learned about yet.

+
+ +

HTML Documents

+

All HTML documents must start with a document type declaration: <!DOCTYPE html>.

+

The HTML document itself begins with <html> and ends with </html>.

+

The visible part of the HTML document is between <body> and </body>.

+
+

Example

+
+ <!DOCTYPE html>
<html>
<body>

<h1>My First Heading</h1>
<p>My first paragraph.</p>

</body>
</html>
+ Try it Yourself » +
+
+ +

The <!DOCTYPE> Declaration

+

The <!DOCTYPE> declaration represents the document type, and helps browsers to display web pages correctly.

+

It must only appear once, at the top of the page (before any HTML tags).

+

The <!DOCTYPE> declaration is not case sensitive.

+

The <!DOCTYPE> declaration for HTML5 is:

+
+
+ <!DOCTYPE html>
+
+
+ +

HTML Headings

+

HTML headings are defined with the <h1> to <h6> tags.

+

<h1> defines the most important heading. <h6> defines the least important + heading: 

+
+

Example

+
+ <h1>This is heading 1</h1>
+ <h2>This is heading 2</h2>
+ <h3>This is heading 3</h3> +
+ Try it Yourself » +
+ +
+
+ + + +
+ +
+
+ +

HTML Paragraphs

+

HTML paragraphs are defined with the <p> tag:

+
+

Example

+
+ <p>This is a paragraph.</p>
+ <p>This is another paragraph.</p> +
+ Try it Yourself » +
+
+ +

HTML Links

+

HTML links are defined with the <a> tag:

+
+

Example

+
+ <a href="https://www.w3schools.com">This is a link</a> +
+ Try it Yourself » +
+

The link's destination is specified in the href attribute. 

+

Attributes are used to provide additional information about HTML elements.

+

You will learn more about attributes in a later chapter.

+
+ +

HTML Images

+

HTML images are defined with the <img> tag.

+

The source file (src), alternative text (alt), + width, and height are provided as attributes:

+
+

Example

+
+ <img src="w3schools.jpg" alt="W3Schools.com" width="104" height="142"> +
+ Try it Yourself » +
+
+ +

How to View HTML Source?

+

Have you ever seen a Web page and wondered "Hey! How did they do that?"

+

View HTML Source Code:

+

Right-click in an HTML page and select "View Page Source" (in + Chrome) or "View Source" (in Edge), or similar in other browsers. This will open a window + containing the HTML source code of the page.

+

Inspect an HTML Element:

+

Right-click on an element (or a blank area), and choose "Inspect" or + "Inspect Element" to see what elements are made up of (you will see both + the HTML and the CSS). You can also edit the HTML or CSS on-the-fly in the + Elements or Styles panel that opens.

+ +
+ +
+
+ +
+ +
+ + +
+ + + + + + + diff --git a/src/WattleScript.Tests/Templating/Tests/Html/10-github.html b/src/WattleScript.Tests/Templating/Tests/Html/10-github.html new file mode 100644 index 00000000..009db364 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/10-github.html @@ -0,0 +1,1796 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GitHub - WattleScript/wattlescript: WattleScript C# scripting engine. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Skip to content + + + + + + + + + + +
+ +
+ + + + + + + +
+ + + +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + +
+ + +
+ +
+ + + + + +
+
+ +
+ +
+
+ + + main + + + + +
+
+
+ Switch branches/tags + +
+ + + +
+ +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + +
+ + +
+
+
+
+ +
+ +
+ + + + +
+ + + + + + + + +
+ Code + +
+ +
+
+ +
+ + +
+
+ + + + +
+
+

Latest commit

+
+ +
+
 
+
+

Git stats

+ +
+
+
+

Files

+ + + + + Permalink + +
+ + + Failed to load latest commit information. + + + +
+
+
+
Type
+
Name
+
Latest commit message
+
Commit time
+
+ +
+
+ +
+ + + +
+
 
+
+ +
+
 
+
+ +
+
+
+ +
+ +
+ src +
+ +
+
 
+
+ +
+
 
+
+ +
+
+
+ +
+ + + +
+
 
+
+ +
+
 
+
+ +
+
+
+ +
+ + + +
+
 
+
+ +
+
 
+
+ +
+
+
+ +
+ +
+ AUTHORS +
+ +
+
 
+
+ +
+
 
+
+ +
+
+
+ +
+ +
+ LICENSE +
+ +
+
 
+
+ +
+
 
+
+ +
+
+
+ +
+ +
+ README.md +
+ +
+
 
+
+ +
+
 
+
+ +
+
+ +
+ +
+ + +
+ + + + +
+ +
+
+ + +

+ + README.md + + +

+
+
+ + + +
+

WattleScript

+

https://wattlescript.github.io/

+
+

WattleScript is a scripting engine written in C# for runtimes supporting .NET Standard 2.0 and newer. (.NET 4.7.2+, .NET Core 3.1+). It is a dual-language environment, providing support for Lua 5.2 code as well as its own language, Wattle.

+

Using WattleScript is as easy as:

+
var script = new Script();
+script.DoString("print('Hello World!')");
+

WattleScript is based off the tried and tested MoonSharp project, inheriting its VM design and test suite. The design focuses on easy and fast interop with .NET objects and functions.

+

Features

+
    +
  • Wattle scripting language.
  • +
  • Lua mode 99% compatible with Lua 5.2, differences documented here.
  • +
  • Easily configured sandbox for safe execution of untrusted scripts.
  • +
  • Minimal garbage generation at runtime
  • +
  • No external dependencies
  • +
  • Easy and performant interop with CLR objects, with runtime code generation where supported
  • +
  • Source Generator for AOT interop.
  • +
  • Support for awaiting on returned values
  • +
  • Supports dumping/loading bytecode
  • +
  • Support for the complete Lua standard library with very few exceptions (mostly located in the debug module).
  • +
  • json module for loading json into tables safely at runtime.
  • +
+

License

+

WattleScript is licensed under the 3-clause BSD License. See LICENSE for details.

+
+
+
+ +
+ + +
+
+ +
+
+
+

About

+ +

+ WattleScript C# scripting engine. +

+
+ + + wattlescript.github.io + +
+ + +

Resources

+ + +

License

+ + + + + + +

Stars

+ + +

Watchers

+ + +

Forks

+ + +
+
+ + +
+
+

Languages

+
+ + + + +
+ + +
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/10-github.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/10-github.wthtml new file mode 100644 index 00000000..051abd96 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/10-github.wthtml @@ -0,0 +1,1798 @@ +@{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GitHub - WattleScript/wattlescript: WattleScript C# scripting engine. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Skip to content + + + + + + + + + + +
+ +
+ + + + + + + +
+ + + +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + +
+ + +
+ +
+ + + + + +
+
+ +
+ +
+
+ + + main + + + + +
+
+
+ Switch branches/tags + +
+ + + +
+ +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + +
+ + +
+
+
+
+ +
+ +
+ + + + +
+ + + + + + + + +
+ Code + +
+ +
+
+ +
+ + +
+
+ + + + +
+
+

Latest commit

+
+ +
+
 
+
+

Git stats

+ +
+
+
+

Files

+ + + + + Permalink + +
+ + + Failed to load latest commit information. + + + +
+
+
+
Type
+
Name
+
Latest commit message
+
Commit time
+
+ +
+
+ +
+ + + +
+
 
+
+ +
+
 
+
+ +
+
+
+ +
+ +
+ src +
+ +
+
 
+
+ +
+
 
+
+ +
+
+
+ +
+ + + +
+
 
+
+ +
+
 
+
+ +
+
+
+ +
+ + + +
+
 
+
+ +
+
 
+
+ +
+
+
+ +
+ +
+ AUTHORS +
+ +
+
 
+
+ +
+
 
+
+ +
+
+
+ +
+ +
+ LICENSE +
+ +
+
 
+
+ +
+
 
+
+ +
+
+
+ +
+ +
+ README.md +
+ +
+
 
+
+ +
+
 
+
+ +
+
+ +
+ +
+ + +
+ + + + +
+ +
+
+ + +

+ + README.md + + +

+
+
+ + + +
+

WattleScript

+

https://wattlescript.github.io/

+
+

WattleScript is a scripting engine written in C# for runtimes supporting .NET Standard 2.0 and newer. (.NET 4.7.2+, .NET Core 3.1+). It is a dual-language environment, providing support for Lua 5.2 code as well as its own language, Wattle.

+

Using WattleScript is as easy as:

+
var script = new Script();
+script.DoString("print('Hello World!')");
+

WattleScript is based off the tried and tested MoonSharp project, inheriting its VM design and test suite. The design focuses on easy and fast interop with .NET objects and functions.

+

Features

+
    +
  • Wattle scripting language.
  • +
  • Lua mode 99% compatible with Lua 5.2, differences documented here.
  • +
  • Easily configured sandbox for safe execution of untrusted scripts.
  • +
  • Minimal garbage generation at runtime
  • +
  • No external dependencies
  • +
  • Easy and performant interop with CLR objects, with runtime code generation where supported
  • +
  • Source Generator for AOT interop.
  • +
  • Support for awaiting on returned values
  • +
  • Supports dumping/loading bytecode
  • +
  • Support for the complete Lua standard library with very few exceptions (mostly located in the debug module).
  • +
  • json module for loading json into tables safely at runtime.
  • +
+

License

+

WattleScript is licensed under the 3-clause BSD License. See LICENSE for details.

+
+
+
+ +
+ + +
+
+ +
+
+
+

About

+ +

+ WattleScript C# scripting engine. +

+
+ + + wattlescript.github.io + +
+ + +

Resources

+ + +

License

+ + + + + + +

Stars

+ + +

Watchers

+ + +

Forks

+ + +
+
+ + +
+
+

Languages

+
+ + + + +
+ + +
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/11-github-min.html b/src/WattleScript.Tests/Templating/Tests/Html/11-github-min.html new file mode 100644 index 00000000..732108ec --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/11-github-min.html @@ -0,0 +1,200 @@ + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/11-github-min.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/11-github-min.wthtml new file mode 100644 index 00000000..362feaa3 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/11-github-min.wthtml @@ -0,0 +1,202 @@ +@{ + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/12-yt.html b/src/WattleScript.Tests/Templating/Tests/Html/12-yt.html new file mode 100644 index 00000000..674526f0 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/12-yt.html @@ -0,0 +1,75 @@ +Barotrauma - Getting started... like a boss! - YouTube
AboutPressCopyrightContact usCreatorsAdvertiseDevelopersTermsPrivacyPolicy & SafetyHow YouTube worksTest new features
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/12-yt.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/12-yt.wthtml new file mode 100644 index 00000000..90884a79 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/12-yt.wthtml @@ -0,0 +1,77 @@ +@{ +Barotrauma - Getting started... like a boss! - YouTube
AboutPressCopyrightContact usCreatorsAdvertiseDevelopersTermsPrivacyPolicy & SafetyHow YouTube worksTest new features
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/13-yt-min.html b/src/WattleScript.Tests/Templating/Tests/Html/13-yt-min.html new file mode 100644 index 00000000..a5cae8fd --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/13-yt-min.html @@ -0,0 +1 @@ +Click “Customize” to 𝄞 \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/13-yt-min.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/13-yt-min.wthtml new file mode 100644 index 00000000..78190418 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/13-yt-min.wthtml @@ -0,0 +1,3 @@ +@{ +Click “Customize” to 𝄞 +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/14-svg.html b/src/WattleScript.Tests/Templating/Tests/Html/14-svg.html new file mode 100644 index 00000000..0215d299 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/14-svg.html @@ -0,0 +1,199 @@ + + happy_news + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/14-svg.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/14-svg.wthtml new file mode 100644 index 00000000..6b59541d --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/14-svg.wthtml @@ -0,0 +1,201 @@ +@{ + + happy_news + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/15-mathml.html b/src/WattleScript.Tests/Templating/Tests/Html/15-mathml.html new file mode 100644 index 00000000..0ddd3ad5 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/15-mathml.html @@ -0,0 +1,36 @@ + + + x + = + + + + - + b + + ± + + + + b + 2 + + - + + 4 + + a + + c + + + + + + 2 + + a + + + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/15-mathml.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/15-mathml.wthtml new file mode 100644 index 00000000..be483b3a --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/15-mathml.wthtml @@ -0,0 +1,38 @@ +@{ + + + x + = + + + + - + b + + ± + + + + b + 2 + + - + + 4 + + a + + c + + + + + + 2 + + a + + + + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/16-html-encode.html b/src/WattleScript.Tests/Templating/Tests/Html/16-html-encode.html new file mode 100644 index 00000000..b66dd31b --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/16-html-encode.html @@ -0,0 +1 @@ +<div>>;<</div> \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/16-html-encode.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/16-html-encode.wthtml new file mode 100644 index 00000000..0464df3b --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/16-html-encode.wthtml @@ -0,0 +1 @@ +@Html.Encode("
>;<
") \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/17-html-raw.html b/src/WattleScript.Tests/Templating/Tests/Html/17-html-raw.html new file mode 100644 index 00000000..6b6b4a44 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/17-html-raw.html @@ -0,0 +1 @@ +
>;<
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/17-html-raw.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/17-html-raw.wthtml new file mode 100644 index 00000000..3b1d652f --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/17-html-raw.wthtml @@ -0,0 +1 @@ +@Html.Raw("
>;<
") \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/18-lua.html b/src/WattleScript.Tests/Templating/Tests/Html/18-lua.html new file mode 100644 index 00000000..6adb8658 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/18-lua.html @@ -0,0 +1,74 @@ + + + + Lua: demo + + + + + + + + +

+ Lua + Demo +

+ +

+ Try Lua before + downloading it. + Enter your Lua program + or + choose one of the demo programs below. + +

+ +

+

+ +

+ + + + +

+ +

Output

+

+ Your program ran successfully. + + +

+ + Lua 5.4.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio + + + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/18-lua.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/18-lua.wthtml new file mode 100644 index 00000000..4b4b5fae --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/18-lua.wthtml @@ -0,0 +1,76 @@ +@{ + + + + Lua: demo + + + + + + + + +

+ Lua + Demo +

+ +

+ Try Lua before + downloading it. + Enter your Lua program + or + choose one of the demo programs below. + +

+ +

+

+ +

+ + + + +

+ +

Output

+

+ Your program ran successfully. + + +

+ + Lua 5.4.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio + + + + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/19-pandas.html b/src/WattleScript.Tests/Templating/Tests/Html/19-pandas.html new file mode 100644 index 00000000..a62079f4 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/19-pandas.html @@ -0,0 +1,779 @@ + + + + + + + + pandas.concat — pandas 1.5.0.dev0+796.gecfcb35844.dirty documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + +
+
+ + + + + + + + +
+ + +
+ + + +
+ +
+ +
+ + +
+ + + + + + +
+ +
+ +
+

pandas.concat

+
+
+ pandas.concat(objs, axis=0, join='outer', ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=False, copy=True)[source]
+

Concatenate pandas objects along a particular axis with optional set logic + along the other axes.

+

Can also add a layer of hierarchical indexing on the concatenation axis, + which may be useful if the labels are the same (or overlapping) on + the passed axis number.

+
+
Parameters
+
+
objsa sequence or mapping of Series or DataFrame objects

If a mapping is passed, the sorted keys will be used as the keys + argument, unless it is passed, in which case the values will be + selected (see below). Any None objects will be dropped silently unless + they are all None in which case a ValueError will be raised.

+
+
axis{0/’index’, 1/’columns’}, default 0

The axis to concatenate along. + If 0, the outcome is identical to DataFrame.append().

+
+
join{‘inner’, ‘outer’}, default ‘outer’

How to handle indexes on other axis (or axes).

+
+
ignore_indexbool, default False

If True, do not use the index values along the concatenation axis. The + resulting axis will be labeled 0, …, n - 1. This is useful if you are + concatenating objects where the concatenation axis does not have + meaningful indexing information. Note the index values on the other + axes are still respected in the join.

+
+
keyssequence, default None

If multiple levels passed, should contain tuples. Construct + hierarchical index using the passed keys as the outermost level.

+
+
levelslist of sequences, default None

Specific levels (unique values) to use for constructing a + MultiIndex. Otherwise they will be inferred from the keys.

+
+
nameslist, default None

Names for the levels in the resulting hierarchical index.

+
+
verify_integritybool, default False

Check whether the new concatenated axis contains duplicates. This can + be very expensive relative to the actual data concatenation.

+
+
sortbool, default False

Sort non-concatenation axis if it is not already aligned when join + is ‘outer’. + This has no effect when join='inner', which already preserves + the order of the non-concatenation axis.

+
+

Changed in version 1.0.0: Changed to not sort by default.

+
+
+
copybool, default True

If False, do not copy data unnecessarily.

+
+
+
+
Returns
+
+
object, type of objs

When concatenating all Series along the index (axis=0), a + Series is returned. When objs contains at least one + DataFrame, a DataFrame is returned. When concatenating along + the columns (axis=1), a DataFrame is returned.

+
+
+
+
+
+

See also

+
+
DataFrame.join

Join DataFrames using indexes.

+
+
DataFrame.merge

Merge DataFrames by indexes or columns.

+
+
+
+

Notes

+

The keys, levels, and names arguments are all optional.

+

A walkthrough of how this method fits in with other tools for combining + pandas objects can be found here.

+

Examples

+

Combine two Series.

+
>>> s1 = pd.Series(['a', 'b'])
+>>> s2 = pd.Series(['c', 'd'])
+>>> pd.concat([s1, s2])
+0    a
+1    b
+0    c
+1    d
+dtype: object
+
+
+

Clear the existing index and reset it in the result + by setting the ignore_index option to True.

+
>>> pd.concat([s1, s2], ignore_index=True)
+0    a
+1    b
+2    c
+3    d
+dtype: object
+
+
+

Add a hierarchical index at the outermost level of + the data with the keys option.

+
>>> pd.concat([s1, s2], keys=['s1', 's2'])
+s1  0    a
+    1    b
+s2  0    c
+    1    d
+dtype: object
+
+
+

Label the index keys you create with the names option.

+
>>> pd.concat([s1, s2], keys=['s1', 's2'],
+...           names=['Series name', 'Row ID'])
+Series name  Row ID
+s1           0         a
+             1         b
+s2           0         c
+             1         d
+dtype: object
+
+
+

Combine two DataFrame objects with identical columns.

+
>>> df1 = pd.DataFrame([['a', 1], ['b', 2]],
+...                    columns=['letter', 'number'])
+>>> df1
+  letter  number
+0      a       1
+1      b       2
+>>> df2 = pd.DataFrame([['c', 3], ['d', 4]],
+...                    columns=['letter', 'number'])
+>>> df2
+  letter  number
+0      c       3
+1      d       4
+>>> pd.concat([df1, df2])
+  letter  number
+0      a       1
+1      b       2
+0      c       3
+1      d       4
+
+
+

Combine DataFrame objects with overlapping columns + and return everything. Columns outside the intersection will + be filled with NaN values.

+
>>> df3 = pd.DataFrame([['c', 3, 'cat'], ['d', 4, 'dog']],
+...                    columns=['letter', 'number', 'animal'])
+>>> df3
+  letter  number animal
+0      c       3    cat
+1      d       4    dog
+>>> pd.concat([df1, df3], sort=False)
+  letter  number animal
+0      a       1    NaN
+1      b       2    NaN
+0      c       3    cat
+1      d       4    dog
+
+
+

Combine DataFrame objects with overlapping columns + and return only those that are shared by passing inner to + the join keyword argument.

+
>>> pd.concat([df1, df3], join="inner")
+  letter  number
+0      a       1
+1      b       2
+0      c       3
+1      d       4
+
+
+

Combine DataFrame objects horizontally along the x axis by + passing in axis=1.

+
>>> df4 = pd.DataFrame([['bird', 'polly'], ['monkey', 'george']],
+...                    columns=['animal', 'name'])
+>>> pd.concat([df1, df4], axis=1)
+  letter  number  animal    name
+0      a       1    bird   polly
+1      b       2  monkey  george
+
+
+

Prevent the result from including duplicate index values with the + verify_integrity option.

+
>>> df5 = pd.DataFrame([1], index=['a'])
+>>> df5
+   0
+a  1
+>>> df6 = pd.DataFrame([2], index=['a'])
+>>> df6
+   0
+a  2
+>>> pd.concat([df5, df6], verify_integrity=True)
+Traceback (most recent call last):
+    ...
+ValueError: Indexes have overlapping values: ['a']
+
+
+

Append a single row to the end of a DataFrame object.

+
>>> a = pd.DataFrame({"A": 1, "B": 2}, index=[0])
+>>> a
+    A   B
+0   1   2
+>>> b = pd.DataFrame({"A": 3}, index=[0])
+>>> b
+    A
+0   3
+>>> for rowIndex, row in b.iterrows():
+>>>     print(pd.concat([a, row.to_frame().T], ignore_index=True))
+   A    B
+0  1  2.0
+1  3  NaN
+
+
+
+ +
+ + +
+ + + + + +
+ + +
+
+ + +
+
+ + + + + +
+
+ + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/19-pandas.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/19-pandas.wthtml new file mode 100644 index 00000000..d650edf0 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/19-pandas.wthtml @@ -0,0 +1,781 @@ +@{ + + + + + + + + pandas.concat — pandas 1.5.0.dev0+796.gecfcb35844.dirty documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+ + +
+ + + +
+ +
+ +
+ + +
+ + + + + + +
+ +
+ +
+

pandas.concat

+
+
+ pandas.concat(objs, axis=0, join='outer', ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=False, copy=True)[source]
+

Concatenate pandas objects along a particular axis with optional set logic + along the other axes.

+

Can also add a layer of hierarchical indexing on the concatenation axis, + which may be useful if the labels are the same (or overlapping) on + the passed axis number.

+
+
Parameters
+
+
objsa sequence or mapping of Series or DataFrame objects

If a mapping is passed, the sorted keys will be used as the keys + argument, unless it is passed, in which case the values will be + selected (see below). Any None objects will be dropped silently unless + they are all None in which case a ValueError will be raised.

+
+
axis{0/’index’, 1/’columns’}, default 0

The axis to concatenate along. + If 0, the outcome is identical to DataFrame.append().

+
+
join{‘inner’, ‘outer’}, default ‘outer’

How to handle indexes on other axis (or axes).

+
+
ignore_indexbool, default False

If True, do not use the index values along the concatenation axis. The + resulting axis will be labeled 0, …, n - 1. This is useful if you are + concatenating objects where the concatenation axis does not have + meaningful indexing information. Note the index values on the other + axes are still respected in the join.

+
+
keyssequence, default None

If multiple levels passed, should contain tuples. Construct + hierarchical index using the passed keys as the outermost level.

+
+
levelslist of sequences, default None

Specific levels (unique values) to use for constructing a + MultiIndex. Otherwise they will be inferred from the keys.

+
+
nameslist, default None

Names for the levels in the resulting hierarchical index.

+
+
verify_integritybool, default False

Check whether the new concatenated axis contains duplicates. This can + be very expensive relative to the actual data concatenation.

+
+
sortbool, default False

Sort non-concatenation axis if it is not already aligned when join + is ‘outer’. + This has no effect when join='inner', which already preserves + the order of the non-concatenation axis.

+
+

Changed in version 1.0.0: Changed to not sort by default.

+
+
+
copybool, default True

If False, do not copy data unnecessarily.

+
+
+
+
Returns
+
+
object, type of objs

When concatenating all Series along the index (axis=0), a + Series is returned. When objs contains at least one + DataFrame, a DataFrame is returned. When concatenating along + the columns (axis=1), a DataFrame is returned.

+
+
+
+
+
+

See also

+
+
DataFrame.join

Join DataFrames using indexes.

+
+
DataFrame.merge

Merge DataFrames by indexes or columns.

+
+
+
+

Notes

+

The keys, levels, and names arguments are all optional.

+

A walkthrough of how this method fits in with other tools for combining + pandas objects can be found here.

+

Examples

+

Combine two Series.

+
>>> s1 = pd.Series(['a', 'b'])
+>>> s2 = pd.Series(['c', 'd'])
+>>> pd.concat([s1, s2])
+0    a
+1    b
+0    c
+1    d
+dtype: object
+
+
+

Clear the existing index and reset it in the result + by setting the ignore_index option to True.

+
>>> pd.concat([s1, s2], ignore_index=True)
+0    a
+1    b
+2    c
+3    d
+dtype: object
+
+
+

Add a hierarchical index at the outermost level of + the data with the keys option.

+
>>> pd.concat([s1, s2], keys=['s1', 's2'])
+s1  0    a
+    1    b
+s2  0    c
+    1    d
+dtype: object
+
+
+

Label the index keys you create with the names option.

+
>>> pd.concat([s1, s2], keys=['s1', 's2'],
+...           names=['Series name', 'Row ID'])
+Series name  Row ID
+s1           0         a
+             1         b
+s2           0         c
+             1         d
+dtype: object
+
+
+

Combine two DataFrame objects with identical columns.

+
>>> df1 = pd.DataFrame([['a', 1], ['b', 2]],
+...                    columns=['letter', 'number'])
+>>> df1
+  letter  number
+0      a       1
+1      b       2
+>>> df2 = pd.DataFrame([['c', 3], ['d', 4]],
+...                    columns=['letter', 'number'])
+>>> df2
+  letter  number
+0      c       3
+1      d       4
+>>> pd.concat([df1, df2])
+  letter  number
+0      a       1
+1      b       2
+0      c       3
+1      d       4
+
+
+

Combine DataFrame objects with overlapping columns + and return everything. Columns outside the intersection will + be filled with NaN values.

+
>>> df3 = pd.DataFrame([['c', 3, 'cat'], ['d', 4, 'dog']],
+...                    columns=['letter', 'number', 'animal'])
+>>> df3
+  letter  number animal
+0      c       3    cat
+1      d       4    dog
+>>> pd.concat([df1, df3], sort=False)
+  letter  number animal
+0      a       1    NaN
+1      b       2    NaN
+0      c       3    cat
+1      d       4    dog
+
+
+

Combine DataFrame objects with overlapping columns + and return only those that are shared by passing inner to + the join keyword argument.

+
>>> pd.concat([df1, df3], join="inner")
+  letter  number
+0      a       1
+1      b       2
+0      c       3
+1      d       4
+
+
+

Combine DataFrame objects horizontally along the x axis by + passing in axis=1.

+
>>> df4 = pd.DataFrame([['bird', 'polly'], ['monkey', 'george']],
+...                    columns=['animal', 'name'])
+>>> pd.concat([df1, df4], axis=1)
+  letter  number  animal    name
+0      a       1    bird   polly
+1      b       2  monkey  george
+
+
+

Prevent the result from including duplicate index values with the + verify_integrity option.

+
>>> df5 = pd.DataFrame([1], index=['a'])
+>>> df5
+   0
+a  1
+>>> df6 = pd.DataFrame([2], index=['a'])
+>>> df6
+   0
+a  2
+>>> pd.concat([df5, df6], verify_integrity=True)
+Traceback (most recent call last):
+    ...
+ValueError: Indexes have overlapping values: ['a']
+
+
+

Append a single row to the end of a DataFrame object.

+
>>> a = pd.DataFrame({"A": 1, "B": 2}, index=[0])
+>>> a
+    A   B
+0   1   2
+>>> b = pd.DataFrame({"A": 3}, index=[0])
+>>> b
+    A
+0   3
+>>> for rowIndex, row in b.iterrows():
+>>>     print(pd.concat([a, row.to_frame().T], ignore_index=True))
+   A    B
+0  1  2.0
+1  3  NaN
+
+
+
+ +
+ + +
+ + + + + +
+ + +
+
+ + +
+
+ + + + + +
+
+ + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/2-w3s-block.html b/src/WattleScript.Tests/Templating/Tests/Html/2-w3s-block.html new file mode 100644 index 00000000..672a8a56 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/2-w3s-block.html @@ -0,0 +1,1323 @@ + + + HTML Basic + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + Tutorials + References + Exercises + Videos + Pro NEW + + Menu + +
+
+ + +
+ + +
+ + + + +
+
+
+ + + HTML + CSS + JAVASCRIPT + SQL + PYTHON + PHP + BOOTSTRAP + HOW TO + W3.CSS + JAVA + JQUERY + C + C++ + C# + R + React + + + + + + + + +
+ +
+ +
+ +
+ + + + + + + + +
+
+ + + + + + +
+
+
+ +

HTML Tutorial

+ HTML HOME + HTML Introduction + HTML Editors + HTML Basic + HTML Elements + HTML Attributes + HTML Headings + HTML Paragraphs + HTML Styles + HTML Formatting + HTML Quotations + HTML Comments + HTML Colors +
+ Colors + RGB + HEX + HSL +
+ HTML CSS + HTML Links + + HTML Images + + HTML Favicon + HTML Tables + + + + + HTML Lists + + HTML Block & Inline + HTML Classes + HTML Id + HTML Iframes + HTML JavaScript + HTML File Paths + HTML Head + HTML Layout + HTML Responsive + HTML Computercode + HTML Semantics + HTML Style Guide + HTML Entities + HTML Symbols + HTML Emojis + HTML Charset + HTML URL Encode + HTML vs. XHTML +
+

HTML Forms

+ HTML Forms + HTML Form Attributes + HTML Form Elements + HTML Input Types + HTML Input Attributes + HTML Input Form Attributes +
+

HTML Graphics

+ HTML Canvas + HTML SVG +
+

HTML Media

+ HTML Media + HTML Video + HTML Audio + HTML Plug-ins + HTML YouTube +
+

HTML APIs

+ HTML Geolocation + HTML Drag/Drop + HTML Web Storage + HTML Web Workers + HTML SSE +
+

HTML Examples

+ HTML Examples + HTML Quiz + HTML Exercises + HTML Certificate + HTML Summary + HTML Accessibility +
+

HTML References

+ HTML Tag List + HTML Attributes + HTML Global Attributes + HTML Browser Support + HTML Events + HTML Colors + HTML Canvas + HTML Audio/Video + HTML Doctypes + HTML Character Sets + HTML URL Encode + HTML Lang Codes + HTTP Messages + HTTP Methods + PX to EM Converter + Keyboard Shortcuts +

+
+
+
+
+
+
+
+ + + +
+ + +
+

HTML Basic Examples

+ +
+

In this chapter we will show some basic HTML examples.

+

Don't worry if we use tags you have not learned about yet.

+
+ +

HTML Documents

+

All HTML documents must start with a document type declaration: <!DOCTYPE html>.

+

The HTML document itself begins with <html> and ends with </html>.

+

The visible part of the HTML document is between <body> and </body>.

+
+

Example

+
+ <!DOCTYPE html>
<html>
<body>

<h1>My First Heading</h1>
<p>My first paragraph.</p>

</body>
</html>
+ Try it Yourself » +
+
+ +

The <!DOCTYPE> Declaration

+

The <!DOCTYPE> declaration represents the document type, and helps browsers to display web pages correctly.

+

It must only appear once, at the top of the page (before any HTML tags).

+

The <!DOCTYPE> declaration is not case sensitive.

+

The <!DOCTYPE> declaration for HTML5 is:

+
+
+ <!DOCTYPE html>
+
+
+ +

HTML Headings

+

HTML headings are defined with the <h1> to <h6> tags.

+

<h1> defines the most important heading. <h6> defines the least important + heading: 

+
+

Example

+
+ <h1>This is heading 1</h1>
+ <h2>This is heading 2</h2>
+ <h3>This is heading 3</h3> +
+ Try it Yourself » +
+ +
+
+ + + +
+ +
+
+ +

HTML Paragraphs

+

HTML paragraphs are defined with the <p> tag:

+
+

Example

+
+ <p>This is a paragraph.</p>
+ <p>This is another paragraph.</p> +
+ Try it Yourself » +
+
+ +

HTML Links

+

HTML links are defined with the <a> tag:

+
+

Example

+
+ <a href="https://www.w3schools.com">This is a link</a> +
+ Try it Yourself » +
+

The link's destination is specified in the href attribute. 

+

Attributes are used to provide additional information about HTML elements.

+

You will learn more about attributes in a later chapter.

+
+ +

HTML Images

+

HTML images are defined with the <img> tag.

+

The source file (src), alternative text (alt), + width, and height are provided as attributes:

+
+

Example

+
+ <img src="w3schools.jpg" alt="W3Schools.com" width="104" height="142"> +
+ Try it Yourself » +
+
+ +

How to View HTML Source?

+

Have you ever seen a Web page and wondered "Hey! How did they do that?"

+

View HTML Source Code:

+

Right-click in an HTML page and select "View Page Source" (in + Chrome) or "View Source" (in Edge), or similar in other browsers. This will open a window + containing the HTML source code of the page.

+

Inspect an HTML Element:

+

Right-click on an element (or a blank area), and choose "Inspect" or + "Inspect Element" to see what elements are made up of (you will see both + the HTML and the CSS). You can also edit the HTML or CSS on-the-fly in the + Elements or Styles panel that opens.

+ +
+ +
+
+ +
+ +
+ + +
+ + + + + + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/2-w3s-block.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/2-w3s-block.wthtml new file mode 100644 index 00000000..1823c90e --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/2-w3s-block.wthtml @@ -0,0 +1,1325 @@ +@{ + + + HTML Basic + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + Tutorials + References + Exercises + Videos + Pro NEW + + Menu + +
+
+ + +
+ + +
+ + + + +
+
+
+ + + HTML + CSS + JAVASCRIPT + SQL + PYTHON + PHP + BOOTSTRAP + HOW TO + W3.CSS + JAVA + JQUERY + C + C++ + C# + R + React + + + + + + + + +
+ +
+ +
+ +
+ + + + + + + + +
+
+ + + + + + +
+
+
+ +

HTML Tutorial

+ HTML HOME + HTML Introduction + HTML Editors + HTML Basic + HTML Elements + HTML Attributes + HTML Headings + HTML Paragraphs + HTML Styles + HTML Formatting + HTML Quotations + HTML Comments + HTML Colors +
+ Colors + RGB + HEX + HSL +
+ HTML CSS + HTML Links + + HTML Images + + HTML Favicon + HTML Tables + + + + + HTML Lists + + HTML Block & Inline + HTML Classes + HTML Id + HTML Iframes + HTML JavaScript + HTML File Paths + HTML Head + HTML Layout + HTML Responsive + HTML Computercode + HTML Semantics + HTML Style Guide + HTML Entities + HTML Symbols + HTML Emojis + HTML Charset + HTML URL Encode + HTML vs. XHTML +
+

HTML Forms

+ HTML Forms + HTML Form Attributes + HTML Form Elements + HTML Input Types + HTML Input Attributes + HTML Input Form Attributes +
+

HTML Graphics

+ HTML Canvas + HTML SVG +
+

HTML Media

+ HTML Media + HTML Video + HTML Audio + HTML Plug-ins + HTML YouTube +
+

HTML APIs

+ HTML Geolocation + HTML Drag/Drop + HTML Web Storage + HTML Web Workers + HTML SSE +
+

HTML Examples

+ HTML Examples + HTML Quiz + HTML Exercises + HTML Certificate + HTML Summary + HTML Accessibility +
+

HTML References

+ HTML Tag List + HTML Attributes + HTML Global Attributes + HTML Browser Support + HTML Events + HTML Colors + HTML Canvas + HTML Audio/Video + HTML Doctypes + HTML Character Sets + HTML URL Encode + HTML Lang Codes + HTTP Messages + HTTP Methods + PX to EM Converter + Keyboard Shortcuts +

+
+
+
+
+
+
+
+ + + +
+ + +
+

HTML Basic Examples

+ +
+

In this chapter we will show some basic HTML examples.

+

Don't worry if we use tags you have not learned about yet.

+
+ +

HTML Documents

+

All HTML documents must start with a document type declaration: <!DOCTYPE html>.

+

The HTML document itself begins with <html> and ends with </html>.

+

The visible part of the HTML document is between <body> and </body>.

+
+

Example

+
+ <!DOCTYPE html>
<html>
<body>

<h1>My First Heading</h1>
<p>My first paragraph.</p>

</body>
</html>
+ Try it Yourself » +
+
+ +

The <!DOCTYPE> Declaration

+

The <!DOCTYPE> declaration represents the document type, and helps browsers to display web pages correctly.

+

It must only appear once, at the top of the page (before any HTML tags).

+

The <!DOCTYPE> declaration is not case sensitive.

+

The <!DOCTYPE> declaration for HTML5 is:

+
+
+ <!DOCTYPE html>
+
+
+ +

HTML Headings

+

HTML headings are defined with the <h1> to <h6> tags.

+

<h1> defines the most important heading. <h6> defines the least important + heading: 

+
+

Example

+
+ <h1>This is heading 1</h1>
+ <h2>This is heading 2</h2>
+ <h3>This is heading 3</h3> +
+ Try it Yourself » +
+ +
+
+ + + +
+ +
+
+ +

HTML Paragraphs

+

HTML paragraphs are defined with the <p> tag:

+
+

Example

+
+ <p>This is a paragraph.</p>
+ <p>This is another paragraph.</p> +
+ Try it Yourself » +
+
+ +

HTML Links

+

HTML links are defined with the <a> tag:

+
+

Example

+
+ <a href="https://www.w3schools.com">This is a link</a> +
+ Try it Yourself » +
+

The link's destination is specified in the href attribute. 

+

Attributes are used to provide additional information about HTML elements.

+

You will learn more about attributes in a later chapter.

+
+ +

HTML Images

+

HTML images are defined with the <img> tag.

+

The source file (src), alternative text (alt), + width, and height are provided as attributes:

+
+

Example

+
+ <img src="w3schools.jpg" alt="W3Schools.com" width="104" height="142"> +
+ Try it Yourself » +
+
+ +

How to View HTML Source?

+

Have you ever seen a Web page and wondered "Hey! How did they do that?"

+

View HTML Source Code:

+

Right-click in an HTML page and select "View Page Source" (in + Chrome) or "View Source" (in Edge), or similar in other browsers. This will open a window + containing the HTML source code of the page.

+

Inspect an HTML Element:

+

Right-click on an element (or a blank area), and choose "Inspect" or + "Inspect Element" to see what elements are made up of (you will see both + the HTML and the CSS). You can also edit the HTML or CSS on-the-fly in the + Elements or Styles panel that opens.

+ +
+ +
+
+ +
+ +
+ + +
+ + + + + + + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/20-google-images-sminem-slow.html b/src/WattleScript.Tests/Templating/Tests/Html/20-google-images-sminem-slow.html new file mode 100644 index 00000000..b06c87a2 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/20-google-images-sminem-slow.html @@ -0,0 +1,292 @@ +sminem - Google Search

Accessibility Links

Settings

Search Modes

AllImagesVideosNewsShopping
Quick Settings
See all settings
Appearance
Google uses cookies to deliver its services, to personalize ads, and to analyze traffic. You can adjust your privacy controls anytime in your Google settings.

Search Results

Image Results

Sminem – Meaning & Origin 2022 (Term explained)

Sminem – Meaning & Origin 2022 (Term explained)
Sminem – Meaning & Origin 2022 (Term ...
slanglang.net

GRADUATE SMINEM | Foundation

GRADUATE SMINEM | Foundation
GRADUATE SMINEM | Foundation
foundation.app

Sminem 3838 (@SminemPompEt) / Twitter

Sminem 3838 (@SminemPompEt) / Twitter
Sminem 3838 (@SminemPompEt) / Twitter
twitter.com

Who Is Sminem? - The Russian Boy 4chan Turned Into A Meme - YouTube

Who Is Sminem? - The Russian Boy 4chan Turned Into A Meme - YouTube
Who Is Sminem? - The Russian Boy 4chan ...
youtube.com

Komunita služby Steam :: :: sminem <>

Komunita služby Steam :: :: sminem <>
Komunita služby Steam :: :: sminem <>
steamcommunity.com

I'm sorry for posting that (Akko Sminem) : r/LittleWitchAcademia

I'm sorry for posting that (Akko Sminem) : r/LittleWitchAcademia
I'm sorry for posting that (Akko Sminem ...
reddit.com

Sminem TikTok (eng sub) [1] - YouTube

Sminem TikTok (eng sub) [1] - YouTube
Sminem TikTok (eng sub) [1] - YouTube
youtube.com

Koupit Unisex Fashion TShirt boy sminem cool Print Plus Size XS-6XL T-Shirt 100%Cotton Tops O Neck Short Sleeve Tees za dobrou cenu — doprava zdarma, skutečné recenze s fotkami — Joom

Koupit Unisex Fashion TShirt boy sminem cool Print Plus Size XS-6XL T-Shirt  100%Cotton Tops O Neck Short Sleeve Tees za dobrou cenu — doprava zdarma,  skutečné recenze s fotkami — Joom
Koupit Unisex Fashion TShirt boy sminem ...
joom.com · Out of stock

Stream Joseph (Sminem) music | Listen to songs, albums, playlists for free on SoundCloud

Stream Joseph (Sminem) music | Listen to songs, albums, playlists for free  on SoundCloud
Stream Joseph (Sminem) music | Listen ...
soundcloud.com

Anybody else got Sminem? : r/enlistedgame

Anybody else got Sminem? : r/enlistedgame
Anybody else got Sminem? : r/enlistedgame
reddit.com

Hey boy Sminem stop... - Bogposting - Take Your Bog Pill | Facebook

Hey boy Sminem stop... - Bogposting - Take Your Bog Pill | Facebook
Hey boy Sminem stop... - Bogposting ...
facebook.com

Sminem - Profile | OpenSea

Sminem - Profile | OpenSea
Sminem - Profile | OpenSea
opensea.io

Sminem Bogdanoff GIF - Sminem Bogdanoff Gme - Discover & Share GIFs

Sminem Bogdanoff GIF - Sminem Bogdanoff Gme - Discover & Share GIFs
Sminem Bogdanoff GIF - Sminem Bogdanoff ...
tenor.com

Sminem on chrismas | Sminem | Know Your Meme

Sminem on chrismas | Sminem | Know Your Meme
Sminem on chrismas | Sminem | Know Your ...
knowyourmeme.com

Sminem with a phone Blank Template - Imgflip

Sminem with a phone Blank Template - Imgflip
Sminem with a phone Blank Template ...
imgflip.com

BOY SMINEM - Rarible | OpenSea

BOY SMINEM - Rarible | OpenSea
BOY SMINEM - Rarible | OpenSea
opensea.io

Boy Sminem watches over... - Scenic Depictions of Slavic Life | Facebook

Boy Sminem watches over... - Scenic Depictions of Slavic Life | Facebook
Boy Sminem watches over... - Scenic ...
facebook.com

Image Results

Boy Sminem Cool T Shirt Sminem So Cool Russia A Normal Day In Russia Reddit 4chan Meme Dank Meme Crypto Cryptocurrency 2454R|T-Shirts| - AliExpress

Boy Sminem Cool T Shirt Sminem So Cool Russia A Normal Day In Russia Reddit  4chan Meme Dank Meme Crypto Cryptocurrency 2454R|T-Shirts| - AliExpress
Boy Sminem Cool T Shirt Sminem So Cool ...
aliexpress.com · In stock

The SMINEM Collection | Foundation

The SMINEM Collection | Foundation
The SMINEM Collection | Foundation
foundation.app

Boy Sminem | Character | zKillboard

Boy Sminem | Character | zKillboard
Boy Sminem | Character | zKillboard
zkillboard.com

Maschine 📉 on Twitter: "@CryptoMessiah Must love #Sminem https://t.co/YByHOX6dcQ" / Twitter

Maschine 📉 on Twitter: "@CryptoMessiah Must love #Sminem  https://t.co/YByHOX6dcQ" / Twitter
CryptoMessiah Must love #Sminem https ...
twitter.com

Objevuj oblíbená videa na téma Sminem | TikTok

Objevuj oblíbená videa na téma Sminem | TikTok
videa na téma Sminem | TikTok
tiktok.com

Sminem Green GIF - Sminem Green Stand - Discover & Share GIFs

Sminem Green GIF - Sminem Green Stand - Discover & Share GIFs
Sminem Green GIF - Sminem Green Stand ...
tenor.com

CHADNEM | Sminem | Know Your Meme

CHADNEM | Sminem | Know Your Meme
CHADNEM | Sminem | Know Your Meme
knowyourmeme.com

Sminem HOPE : Clothing, Shoes & Jewelry

Sminem HOPE : Clothing, Shoes & Jewelry
Sminem HOPE : Clothing, Shoes & Jewelry
amazon.com

RETURN OF SMINEM - YouTube

RETURN OF SMINEM - YouTube
RETURN OF SMINEM - YouTube
youtube.com

Invest in Sminem. We found him fellows. He's coming… : r/MemeEconomy

Invest in Sminem. We found him fellows. He's coming… : r/MemeEconomy
Invest in Sminem. We found him fellows ...
reddit.com

Squatting Slavs In Tracksuits - Sminem President , big biznis! | Facebook

Squatting Slavs In Tracksuits - Sminem President , big biznis! | Facebook
Squatting Slavs In Tracksuits - Sminem ...
m.facebook.com

Sminem (@ru_sminem) / Twitter

Sminem (@ru_sminem) / Twitter
Sminem (@ru_sminem) / Twitter
twitter.com

Birthday Sminem | Sminem | Know Your Meme

Birthday Sminem | Sminem | Know Your Meme
Birthday Sminem | Sminem | Know Your Meme
knowyourmeme.com

A Brief History of Sminem - YouTube

A Brief History of Sminem - YouTube
A Brief History of Sminem - YouTube
youtube.com

Know Your Meme on Twitter: "The Sminem Boy Cool NFT project is slated to be auctioned off as a unique crypto-collectible broken up into more than 12K pieces. To learn more, we

Know Your Meme on Twitter: "The Sminem Boy Cool NFT project is slated to be  auctioned off as a unique crypto-collectible broken up into more than 12K  pieces. To learn more, we
The Sminem Boy Cool NFT project is ...
twitter.com

Workshop služby Steam::SMINEM VS BOGDANOFF

Workshop služby Steam::SMINEM VS BOGDANOFF
Workshop služby Steam::SMINEM VS BOGDANOFF
steamcommunity.com

Player statistics - Sminem | CS:GO Stats

Player statistics - Sminem | CS:GO Stats
Player statistics - Sminem | CS:GO Stats
csgostats.gg

SMINEM's Music Profile | Last.fm

SMINEM's Music Profile | Last.fm
SMINEM's Music Profile | Last.fm
last.fm
Wait while more content is being loaded
Google apps
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/20-google-images-sminem-slow.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/20-google-images-sminem-slow.wthtml new file mode 100644 index 00000000..8ed63a92 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/20-google-images-sminem-slow.wthtml @@ -0,0 +1,294 @@ +@!{ +sminem - Google Search

Accessibility Links

Settings

Search Modes

AllImagesVideosNewsShopping
Quick Settings
See all settings
Appearance
Google uses cookies to deliver its services, to personalize ads, and to analyze traffic. You can adjust your privacy controls anytime in your Google settings.

Search Results

Image Results

Sminem – Meaning & Origin 2022 (Term explained)

Sminem – Meaning & Origin 2022 (Term explained)
Sminem – Meaning & Origin 2022 (Term ...
slanglang.net

GRADUATE SMINEM | Foundation

GRADUATE SMINEM | Foundation
GRADUATE SMINEM | Foundation
foundation.app

Sminem 3838 (@SminemPompEt) / Twitter

Sminem 3838 (@SminemPompEt) / Twitter
Sminem 3838 (@SminemPompEt) / Twitter
twitter.com

Who Is Sminem? - The Russian Boy 4chan Turned Into A Meme - YouTube

Who Is Sminem? - The Russian Boy 4chan Turned Into A Meme - YouTube
Who Is Sminem? - The Russian Boy 4chan ...
youtube.com

Komunita služby Steam :: :: sminem <>

Komunita služby Steam :: :: sminem <>
Komunita služby Steam :: :: sminem <>
steamcommunity.com

I'm sorry for posting that (Akko Sminem) : r/LittleWitchAcademia

I'm sorry for posting that (Akko Sminem) : r/LittleWitchAcademia
I'm sorry for posting that (Akko Sminem ...
reddit.com

Sminem TikTok (eng sub) [1] - YouTube

Sminem TikTok (eng sub) [1] - YouTube
Sminem TikTok (eng sub) [1] - YouTube
youtube.com

Koupit Unisex Fashion TShirt boy sminem cool Print Plus Size XS-6XL T-Shirt 100%Cotton Tops O Neck Short Sleeve Tees za dobrou cenu — doprava zdarma, skutečné recenze s fotkami — Joom

Koupit Unisex Fashion TShirt boy sminem cool Print Plus Size XS-6XL T-Shirt  100%Cotton Tops O Neck Short Sleeve Tees za dobrou cenu — doprava zdarma,  skutečné recenze s fotkami — Joom
Koupit Unisex Fashion TShirt boy sminem ...
joom.com · Out of stock

Stream Joseph (Sminem) music | Listen to songs, albums, playlists for free on SoundCloud

Stream Joseph (Sminem) music | Listen to songs, albums, playlists for free  on SoundCloud
Stream Joseph (Sminem) music | Listen ...
soundcloud.com

Anybody else got Sminem? : r/enlistedgame

Anybody else got Sminem? : r/enlistedgame
Anybody else got Sminem? : r/enlistedgame
reddit.com

Hey boy Sminem stop... - Bogposting - Take Your Bog Pill | Facebook

Hey boy Sminem stop... - Bogposting - Take Your Bog Pill | Facebook
Hey boy Sminem stop... - Bogposting ...
facebook.com

Sminem - Profile | OpenSea

Sminem - Profile | OpenSea
Sminem - Profile | OpenSea
opensea.io

Sminem Bogdanoff GIF - Sminem Bogdanoff Gme - Discover & Share GIFs

Sminem Bogdanoff GIF - Sminem Bogdanoff Gme - Discover & Share GIFs
Sminem Bogdanoff GIF - Sminem Bogdanoff ...
tenor.com

Sminem on chrismas | Sminem | Know Your Meme

Sminem on chrismas | Sminem | Know Your Meme
Sminem on chrismas | Sminem | Know Your ...
knowyourmeme.com

Sminem with a phone Blank Template - Imgflip

Sminem with a phone Blank Template - Imgflip
Sminem with a phone Blank Template ...
imgflip.com

BOY SMINEM - Rarible | OpenSea

BOY SMINEM - Rarible | OpenSea
BOY SMINEM - Rarible | OpenSea
opensea.io

Boy Sminem watches over... - Scenic Depictions of Slavic Life | Facebook

Boy Sminem watches over... - Scenic Depictions of Slavic Life | Facebook
Boy Sminem watches over... - Scenic ...
facebook.com

Image Results

Boy Sminem Cool T Shirt Sminem So Cool Russia A Normal Day In Russia Reddit 4chan Meme Dank Meme Crypto Cryptocurrency 2454R|T-Shirts| - AliExpress

Boy Sminem Cool T Shirt Sminem So Cool Russia A Normal Day In Russia Reddit  4chan Meme Dank Meme Crypto Cryptocurrency 2454R|T-Shirts| - AliExpress
Boy Sminem Cool T Shirt Sminem So Cool ...
aliexpress.com · In stock

The SMINEM Collection | Foundation

The SMINEM Collection | Foundation
The SMINEM Collection | Foundation
foundation.app

Boy Sminem | Character | zKillboard

Boy Sminem | Character | zKillboard
Boy Sminem | Character | zKillboard
zkillboard.com

Maschine 📉 on Twitter: "@CryptoMessiah Must love #Sminem https://t.co/YByHOX6dcQ" / Twitter

Maschine 📉 on Twitter: "@CryptoMessiah Must love #Sminem  https://t.co/YByHOX6dcQ" / Twitter
CryptoMessiah Must love #Sminem https ...
twitter.com

Objevuj oblíbená videa na téma Sminem | TikTok

Objevuj oblíbená videa na téma Sminem | TikTok
videa na téma Sminem | TikTok
tiktok.com

Sminem Green GIF - Sminem Green Stand - Discover & Share GIFs

Sminem Green GIF - Sminem Green Stand - Discover & Share GIFs
Sminem Green GIF - Sminem Green Stand ...
tenor.com

CHADNEM | Sminem | Know Your Meme

CHADNEM | Sminem | Know Your Meme
CHADNEM | Sminem | Know Your Meme
knowyourmeme.com

Sminem HOPE : Clothing, Shoes & Jewelry

Sminem HOPE : Clothing, Shoes & Jewelry
Sminem HOPE : Clothing, Shoes & Jewelry
amazon.com

RETURN OF SMINEM - YouTube

RETURN OF SMINEM - YouTube
RETURN OF SMINEM - YouTube
youtube.com

Invest in Sminem. We found him fellows. He's coming… : r/MemeEconomy

Invest in Sminem. We found him fellows. He's coming… : r/MemeEconomy
Invest in Sminem. We found him fellows ...
reddit.com

Squatting Slavs In Tracksuits - Sminem President , big biznis! | Facebook

Squatting Slavs In Tracksuits - Sminem President , big biznis! | Facebook
Squatting Slavs In Tracksuits - Sminem ...
m.facebook.com

Sminem (@ru_sminem) / Twitter

Sminem (@ru_sminem) / Twitter
Sminem (@ru_sminem) / Twitter
twitter.com

Birthday Sminem | Sminem | Know Your Meme

Birthday Sminem | Sminem | Know Your Meme
Birthday Sminem | Sminem | Know Your Meme
knowyourmeme.com

A Brief History of Sminem - YouTube

A Brief History of Sminem - YouTube
A Brief History of Sminem - YouTube
youtube.com

Know Your Meme on Twitter: "The Sminem Boy Cool NFT project is slated to be auctioned off as a unique crypto-collectible broken up into more than 12K pieces. To learn more, we

Know Your Meme on Twitter: "The Sminem Boy Cool NFT project is slated to be  auctioned off as a unique crypto-collectible broken up into more than 12K  pieces. To learn more, we
The Sminem Boy Cool NFT project is ...
twitter.com

Workshop služby Steam::SMINEM VS BOGDANOFF

Workshop služby Steam::SMINEM VS BOGDANOFF
Workshop služby Steam::SMINEM VS BOGDANOFF
steamcommunity.com

Player statistics - Sminem | CS:GO Stats

Player statistics - Sminem | CS:GO Stats
Player statistics - Sminem | CS:GO Stats
csgostats.gg

SMINEM's Music Profile | Last.fm

SMINEM's Music Profile | Last.fm
SMINEM's Music Profile | Last.fm
last.fm
Wait while more content is being loaded
Google apps
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/21-wikipedia-bogdanoff-slow.html b/src/WattleScript.Tests/Templating/Tests/Html/21-wikipedia-bogdanoff-slow.html new file mode 100644 index 00000000..af9228cd --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/21-wikipedia-bogdanoff-slow.html @@ -0,0 +1,765 @@ + + + + + Igor and Grichka Bogdanoff - Wikipedia + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+

Igor and Grichka Bogdanoff

+
+
From Wikipedia, the free encyclopedia
+
+
+ +
+ Jump to navigation + Jump to search +
+ +

+

+
Igor and Grichka Bogdanoff
Présentation équipe DMBC, 10 septembre 2016 - 6.jpg
Grichka (left) and Igor (right) in 2016
Born
Igor Youriévitch Bogdanoff
Grégoire Youriévitch Bogdanoff

(1949-08-29)29 August 1949
DiedIgor: 3 January 2022(2022-01-03) (aged 72)
Grichka: 28 December 2021(2021-12-28) (aged 72)
Paris, France
Other names
+
  • Bogdanoff twins
+
OccupationMedia personalities
Known for
Alma materUniversity of Burgundy
Scientific career
FieldsTheoretical physics
ThesisFluctuations quantiques de la signature de la métrique à l'échelle de Planck (1999)
Doctoral advisorMoshé Flato [fr], Daniel Sternheimer
+
+
+

Igor Youriévitch Bogdanoff (French pronunciation: ​[iɡɔʁ juʁi.evitʃ bɔɡdanɔf]; 29 August 1949 – 3 January 2022) and Grégoire "Grichka" Youriévitch Bogdanoff (French: [ɡʁeɡwaʁ ɡʁiʃka]; 29 August 1949 – 28 December 2021) were French twin television presenters,[1] producers, and essayists who, from the 1970s on, presented various subjects in science fiction, popular science, and cosmology. They were involved in a number of controversies, most notably the Bogdanov affair, in which the brothers were alleged to have written nonsensical advanced physics papers that were nonetheless published in reputable scientific journals. +

+ + +

Early years[edit]

+
The twins' maternal grandmother, Berta Kolowrat-Krakowská
+

Igor and Grichka Bogdanoff were identical twin brothers born to Maria "Maya" Dolores Franzyska Kolowrat-Krakowská (1926–1982) and Yuri Mikhaïlovitch Bogdanoff (1928–2012),[2] an itinerant Russian farm worker, later a painter. Igor Bogdanoff was born 40 minutes before Grichka. They had no connection to, or involvement with, their father's family, and were raised by their maternal grandmother, Countess Bertha Kolowrat-Krakowská (1890–1982),[3] in her castle in southern France. Bertha Kolowrat-Krakowská belonged to the noble Kolowrat family of Bohemia and was married to a member of the Austrian princely house of Colloredo-Mannsfeld.[4] Her pregnancy by African-American tenor Roland Hayes caused her to forfeit access to her four elder children, to her palatial homes in Berlin and Prague, and also her reputation in European society.[3] She tried to sustain her episodic relationship with Hayes after her divorce and his return to the United States, but declined his offer to legally adopt and raise their daughter, who became Igor and Grichka's mother.[3] +

Although the Bogdanoff twins claimed to be descended paternally from a noble Muslim Tatar family traceable to the beginning of the 17th century (originally from Penza, one of whose mirzas converted to Orthodox Christianity, and was rewarded with the title of prince by a decree from Tsar Feodor III; the mirza did not exercise this right, and the title of "Prince Bogdanoff" was lost by the end of the 19th century),[5][6] there is scant evidence for that. Genealogist William Addams Reitwiesner observed: "The Bogdanov twins claim that their father was a member of a princely Russian family. Other than a statement by Dr. Stanislaus Dumin (included in a message posted by the twins on 7 Jan 2005 to the alt.talk.royalty Usenet newsgroup), there isn't much evidence to support this claim."[7] The journalist and documentary filmmaker Maud Guillaumin, author of Le mystère Bogdanoff (L'Archipel, 2019), comprehensively examined the twins' account, noting it to comprise "approximations and historical inaccuracies"; she found that Yuri Bogdanoff had gone to Spain as a young man, and, unable to return to the U.S.S.R. because he would have been considered a spy and imprisoned, went to France and began "a life of wandering from farm to Pyrenean farm" before, in 1948 aged 21, arriving at the castle of his future mother-in-law, "renowned in the Gers for employing Slavs". Guillaumin noted that "the twins totally deny this sad odyssey. They explain that they have found proof that their father was the descendant of a prince, the right arm of Tsar Peter the Great", that "according to them, Youra was a young artist [...] he would have followed 'a solid training as a painter as a free auditor at the Beaux-Arts'", and that "it was there, according to the twins, who love romance, that a "famous writer" met in Paris would have introduced Youra to their grandmother". Guillaumin's interview with the Bogdanoff twins' godmother, Monique David, contradicted their romantic account, and established that the twins' mother, Maya, was pregnant with them at the time of her marriage to Yuri Bogdanoff, who Countess Bertha Kolowrat-Krakowská considered an unworthy match for her daughter. She "chased him away", leading him to be absent from his sons' lives until they were ten years old, and subsequently divorced from Maya.[8][9] +

Besides French, they spoke German, Russian, and English. Their grandmother spoke several languages, as well.[10] +

+

Television shows[edit]

+
Igor (left) and Grichka (right) in the 1990s
+

The brothers began careers in television, hosting several popular programs on science and science fiction.[11][12][13] The first of these, Temps X (Time X), ran from 1979 to 1989[12][14] and introduced several British and American science-fiction series to the French public, including The Prisoner, Star Trek, and Doctor Who, in addition to featuring musical guests such as Jean-Michel Jarre.[15] +

In 2002, the Bogdanoffs launched a new weekly television show, Rayons X (X Rays), on the French public channel France 2. In August 2004, they presented a 90-minute special cosmology program.[16] +

+

Academic careers[edit]

+

Grichka Bogdanoff received a Ph.D. degree in mathematics from the University of Burgundy (Dijon) in 1999.[17][11] In 2002, Igor Bogdanoff received a Ph.D. in theoretical physics from the University of Burgundy.[11] Both brothers received the lowest passing grade of "honorable".[11] +

+

Bogdanov affair[edit]

+ +
Grichka (left) and Igor (right) Bogdanoff in 2010
+

In 2001 and 2002, the brothers published five papers (including "Topological field theory of the initial singularity of spacetime") in peer-reviewed physics journals.[18][19] Controversy over the Bogdanoffs' work began on 22 October 2002, with an email sent by University of Tours physicist Max Niedermaier to University of Pittsburgh physicist Ezra T. Newman.[20] Niedermaier suggested that the Bogdanoffs' Ph.D. theses and papers were "spoof[s]", created by throwing together instances of theoretical-physics jargon, including terminology from string theory: "The abstracts are delightfully meaningless combinations of buzzwords ... which apparently have been taken seriously."[20][21] +

Copies of the email reached American mathematical physicist John C. Baez, and on 23 October he created a discussion thread about the Bogdanoffs' work on the Usenet newsgroup sci.physics.research, titled "Physics bitten by reverse Alan Sokal hoax?"[12][22] Baez was comparing the Bogdanoffs' publications to the 1996 Sokal affair, in which physicist Alan Sokal successfully submitted an intentionally nonsensical paper to a cultural studies journal in order to criticize that field's lax standards for discussing science. The Bogdanoffs quickly became a popular discussion topic, with most respondents agreeing that the papers were flawed.[19] +

The story spread in public media, prompting Niedermaier to offer an apology to the Bogdanoffs, admitting that he had not read the papers himself. The Bogdanoffs' background in entertainment lent some plausibility to the idea that they were attempting a deliberate hoax, but Igor Bogdanoff quickly denied the accusation.[11][19] +

In October 2002, the Bogdanoffs released an email containing apparently supportive statements by Laurent Freidel, then a visiting professor at the Perimeter Institute for Theoretical Physics.[12] Soon after, Freidel denied writing any such remarks, telling the press that he had forwarded a message containing that text to a friend.[12] +

The online discussion was quickly followed by media attention. The Register reported on the dispute on 1 November 2002,[23] and stories in The Chronicle of Higher Education,[12] Nature,[20] The New York Times,[11] and other publications appeared soon after.[24][25] These news stories included commentary by physicists. +

One of the scientists who approved Igor Bogdanoff's thesis, Roman Jackiw of the Massachusetts Institute of Technology, spoke to The New York Times reporter Dennis Overbye. Overbye wrote that Jackiw was intrigued by the thesis, although it contained many points he did not understand. Jackiw defended the thesis.[11] In contrast, Ignatios Antoniadis (of the École Polytechnique), who approved Grichka Bogdanoff's thesis, later reversed his judgment of it. Antoniadis told Le Monde: +

+

I had given a favorable opinion for Grichka's defense, based on a rapid and indulgent reading of the thesis text. Alas, I was completely mistaken. The scientific language was just an appearance behind which hid incompetence and ignorance of even basic physics.[24]

+

The journal Classical and Quantum Gravity (CQG) published one of the Bogdanoffs' papers, titled "Topological field theory of the initial singularity of spacetime";[26] Ian Russell, assistant director of its journals division, later issued a statement stating that "we deployed our standard peer-review process on that paper."[12] After the publication of the article and the publicity surrounding the controversy, mathematician Greg Kuperberg posted to Usenet a statement written by the journal's senior publisher, Andrew Wray, and its co-editor, Hermann Nicolai. The statement read, in part, +

+

Regrettably, despite the best efforts, the refereeing process cannot be 100% effective. Thus the paper ... made it through the review process even though, in retrospect, it does not meet the standards expected of articles in this journal... The paper was discussed extensively at the annual Editorial Board meeting ... and there was general agreement that it should not have been published. Since then several steps have been taken to further improve the peer review process in order to improve the quality assessment on articles submitted to the journal and reduce the likelihood that this could happen again.[27]

+

The statement was quoted in The New York Times,[11] The Chronicle of Higher Education,[12] and Nature.[20] Moreover, Die Zeit quoted Nicolai as saying that had the paper reached his desk, he would have immediately rejected it.[25] +

The Chinese Journal of Physics published Igor Bogdanoff's "The KMS state of spacetime at the Planck scale", while Nuovo Cimento published "KMS space-time at the Planck scale". According to physicist Arun Bala, all of these papers "involved purported applications of quantum theory to understand processes at the dawn of the universe", but ultimately turned out to be a "hoax perpetrated on the physics community."[26] +

Not all review evaluations were positive. Eli Hawkins, acting as a referee on behalf of the Journal of Physics A, suggested rejecting one of the Bogdanoffs' papers: "It would take up too much space to enumerate all the mistakes: indeed it is difficult to say where one error ends and the next begins."[28] +

Eventually, the controversy attracted mainstream media attention, opening new avenues for physicists' comments to be disseminated. Le Monde quoted Alain Connes, recipient of the 1982 Fields Medal, as saying, "I didn't need long to convince myself that they're talking about things that they haven't mastered."[24] The New York Times reported that the physicists David Gross, Carlo Rovelli, and Lee Smolin considered the Bogdanoff papers nonsensical.[11] Nobel laureate Georges Charpak later stated on a French talk show that the Bogdanoffs' presence in the scientific community was "nonexistent".[29][30] +

Robert Oeckl's official MathSciNet review of "Topological field theory of the initial singularity of spacetime" states that the paper is "rife with nonsensical or meaningless statements and suffers from a serious lack of coherence", follows up with several examples to illustrate his point, and concludes that the paper "falls short of scientific standards and appears to have no meaningful content."[31] An official report from the Centre national de la recherche scientifique (CNRS), which became public in 2010, concluded that the paper "ne peut en aucune façon être qualifié de contribution scientifique" ("cannot in any way be considered a scientific contribution").[32][33] +

The CNRS report summarized the Bogdanoffs' theses thus: "Ces thèses n’ont pas de valeur scientifique. […] Rarement aura-t-on vu un travail creux habillé avec une telle sophistication" ("These theses have no scientific value. [...] Rarely have we seen a hollow work dressed with such sophistication").[34][35] +

+

Lawsuits[edit]

+

On December 30, 2004, the Bogdanoffs sued Ciel et Espace for defamation over the publication of a critical article titled "The Mystification of the Bogdanoffs".[36] In September 2006, the case was dismissed after the Bogdanoffs missed court deadlines; they were ordered to pay 2,500 to the magazine's publisher to cover its legal costs.[36][37] There was never a substantive ruling on whether or not the Bogdanoffs had been defamed.[37] +

+ Alain Riazuelo, an astrophysicist at the Institut d'Astrophysique de Paris, participated in many of the online discussions of the Bogdanoffs' work. He posted an unpublished version of Grichka Bogdanoff's Ph.D. thesis on his personal website, along with his critical analysis. Bogdanoff subsequently described this version as "dating from 1991 and too unfinished to be made public". Rather than suing Riazuelo for defamation, Bogdanoff filed a criminal complaint of copyright (droit d'auteur) violation against him in May 2011.[38] +

The police detained and interrogated Riazuelo. He was convicted in March 2012. A fine of €2,000 the court imposed was suspended, and only €1.00 of damages was awarded,[38] but in passing judgement the court stated that the scientist had "lacked prudence", given "the fame of the plaintiff".[39] +

The verdict outraged many scientists, who felt that the police and courts should have no say in a discussion of the scientific merits of a piece of work. In April 2012, a group of 170 scientists published an open letter titled L'affaire Bogdanoff: Liberté, Science et Justice, Des scientifiques revendiquent leur droit au blâme (The Bogdanoff Affair: Liberty, Science and Justice, scientists claim their right of critique).[40] +

In 2014, the Bogdanoffs sued the weekly magazine Marianne for defamation, on account of reporting the magazine had published in 2010[41] which had brought the CNRS report to light. The magazine was eventually ordered to pay €64,000 in damages, much less than the €800,000 each which the Bogdanoffs had originally demanded.[42] The Bogdanoffs also sued the CNRS for €1.2 million in damages, claiming that the CNRS report had "porté atteinte à leur honneur, à leur réputation et à leur crédit" ("undermined their honor, reputation and credit") and calling the report committee a "Stasi scientifique", but a tribunal ruled against them in 2015 and ordered them to pay €2,000.[35][43] +

+

Megatrend University[edit]

+

In 2005, the Bogdanoffs became professors at Megatrend University in Belgrade, where they were appointed to Chairs of Cosmology and made directors of the 'Megatrend Laboratory of Cosmology'.[44][45] Mića Jovanović, the rector and owner of Megatrend University, wrote a preface for the Serbian edition of Avant le Big Bang.[45] Jovanović himself later became embroiled in controversy and resigned his post, when he was found out to not have obtained a Ph.D. at the London School of Economics as he had claimed.[46] This scandal, combined with the presence of the Bogdanoffs, contributed to an atmosphere of controversy surrounding Megatrend.[47] +

+

Personal lives[edit]

+

The Bogdanoff twins, who denied having undergone plastic surgery,[48] became known for their prominent cheekbones and chins. In 2010, The Sydney Morning Herald described the twins' cheekbones as "so high and bulbous as to appear to threaten their owners' vision", adding that the twins' appearance at the Cannes Film Festival had "caused a stir around the world". The Herald noted that the twins' cheekbones had become noticeably larger in the 1990s, and that "growth in their lips and chins continued unabated through the last decade".[49] According to former education minister Luc Ferry, a friend of the brothers, they had both received botox injections for cosmetic treatment.[15] +

The twins became popular Internet memes, especially among enthusiasts of cryptocurrency, jokingly depicting the Bogdanoffs as "all-powerful market makers". Their status as "crypto memes" was covered by several outlets upon their deaths, including CNN, Business Insider, and The Daily Telegraph.[28][50][51] The twins "went along with their meme fame", according to Business Insider, and said they predicted cryptocurrency in the 1980s on Temps X.[51] +

Igor Bogdanoff had six children, four from his first marriage and two from his second.[52] He married his second wife, Amélie de Bourbon-Parme, civilly in Paris on 1 October 2009 and religiously in Chambord two days later.[53] +

+

Deaths[edit]

+

The Bogdanoff twins were both hospitalized, at the Georges Pompidou European Hospital in Paris,[54] in critical condition on 15 December 2021, after contracting COVID-19. Grichka died on 28 December,[55] and Igor died six days later, on 3 January 2022.[56] They were 72 and both were unvaccinated.[57][58][15] The funeral for both twins was held on 10 January 2022, in the Church of the Madeleine, in Paris, France.[59] +

+

Publications[edit]

+

The Bogdanoff brothers published a number of works in science fiction, philosophy and popular science. Since 1991, they signed their books as "Bogdanov", preferring "v" to "ff". +

+
  • Clefs pour la science-fiction (essay), Éditions Seghers, 378 p., Paris, 1976[ISBN missing], BNF:34707099q.
  • +
  • L'Effet science-fiction: à la recherche d'une définition (essay), Éditions Robert Laffont, Paris, 1979, 423 p., ISBN 978-2-221-00411-1, BNF:34650185 g.
  • +
  • Chroniques du "Temps X" (preface by Gérard Klein), Éditions du Guépard, Paris, 1981, 247 p., ISBN 978-2-86527-030-9, BNF: 34734883f.
  • +
  • La Machine fantôme, Éditions J'ai lu, 1985, 251 p., ISBN 978-2-277-21921-7, BNF:34842073t.
  • +
  • La Mémoire double (novel), first as hardcover on Éditions Hachette, Paris, 1985, 381 p., ISBN 978-2-01-011494-6, BNF:348362498; then as pocket book
  • +
  • Dieu et la science: vers le métaréalisme (interviews with Jean Guitton): Hardcover Éditions Grasset, Paris, 1991, 195 p., ISBN 978-2-246-42411-6, BNF: 35458968t; then as a pocketbook
  • +
  • Avant le Big Bang: la création du monde (essay), 2004[60]
  • +
  • Voyage vers l'Instant Zéro, Éditions EPA, Paris, 2006, 185 p., ISBN 978-2-85120-635-0, BNF: 40986028h.
  • +
  • Nous ne sommes pas seuls dans l'univers, Éditions EPA, Paris, 2007, 191 p., ISBN 978-2-85120-664-0, BNF: 411885989.
  • +
  • Au commencement du temps, Éditions Flammarion, Paris, 2009, 317 p., ISBN 978-2-08-120832-2, BNF: 420019981.
  • +
  • Le Visage de Dieu, (with a preface by Robert Woodrow Wilson and endnotes by Jim Peebles, Robert Woodrow Wilson and John Mather, Éditions Grasset, Paris, May 2010, 282 p., ISBN 978-2-246-77231-6, BNF: 42207600f.
  • +
  • Le Dernier Jour des dinosaures Éditions de la Martinière, Octobre 2011, ISBN 978-2732447100
  • +
  • La Pensée de Dieu, (with endnotes by Luis Gonzalez-Mestres), Éditions Grasset, Paris, June 2012, ISBN 978-2-246-78509-5
  • +
  • Le mystère du satellite Planck (Qu'y avait-il avant le Big Bang ?) (with preface and endnotes by Luis Gonzalez-Mestres, Éditions Eyrolles, June 2013, ISBN 978-2-212-55732-9
  • +
  • La Fin du hasard, Éditions Grasset, Paris, Octobre 2013, ISBN 978-2-246-80990-6
  • +
  • 3 minutes pour comprendre la grande théorie du Big Bang (preface by John Mather, end notes by Luis Gonzalez-Mestres, Éditions Le Courrier du Livre, October 2014, ISBN 978-2702911211
+

References[edit]

+
+
    +
  1. ^ Luis Gonzalez-Mestres, L'Énigme Bogdanov, Éditions Télémaque, Paris, 2015, 320 p., ISBN 978-2-7533-0266-2 +
  2. +
  3. ^ "Youra Bogdanoff, père des célèbres frères Igor et Grishka Bogdanoff est décédé cette semaine. D'origine russe, il était né le 28 janvier 1928 à Saint-Pétersbourg. Artiste-peintre, il s'était établi à Saint-Lary avec son épouse Maya, avant la naissance de leurs premiers enfants, Igor et Grichka. Les frères Bogdanoff ont quatre frères et sœurs plus jeunes : François, Laurence, Géraldine et Véronique. Un recueillement en sa mémoire aura lieu le mercredi 8 août, à 11 heures, au cimetière de Saint-Lary. La Dépêche du Midi présente ses condoléances à la famille (Youra Bogdanof)" [father of famous brothers Igor and Grishka Bogdanoff died this week. Of Russian origin, he was born on January 28, 1928 in Saint Petersburg. Artist-painter, he had settled in Saint-Lary with his wife Maya, before the birth of their first children, Igor and Grichka. The Bogdanoff brothers have four younger siblings: François, Laurence, Géraldine and Véronique. A meditation in his memory will take place on Wednesday August 8, at 11 a.m., at the Saint-Lary cemetery. La Dépêche du Midi presents its condolences to the family]. www.ladepeche.fr. +
  4. +
  5. ^ a b c Brooks, Christopher A. Roland Hayes: The Legacy of an American Tenor. Indiana University Press. Bloomington. 2015. pp. 358, 361–62, 366–67, 379. ISBN 978-0-253-01536-5. +
  6. +
  7. ^ Genealogisches Handbuch des Adels, Fürstliche Häuser XIX. "Colloredo-Mannsfeld". C.A. Starke Verlag, 2011, pp. 127–29. (German). ISBN 978-3-7980-0849-6. +
  8. +
  9. ^ Après consultation de tous les nobiliaires faisant autorité, aucun ne mentionne une quelconque famille de prince Bogdanoff : Patrick de Gmeline. « Dictionnaire de la noblesse russe ». Éditions Contrepoint, 1978, Almanach de Gotha 1918, Almanach de Gotha 1940, Almanach de Gotha, 2013. +
  10. +
  11. ^ Cependant, cela ne les prive pas théoriquement de la possibilité de confirmer à nouveau leur droit au titre de prince sur les voies de la grâce du chef de la maison impériale de Russie (selon plusieurs exemples connus) : les Bogdanoff sont de nouveau cités comme famille princière en 1906 dans des dictionnaires généalogiques russes. La reconnaissance par le chef de la maison souveraine royale de Georgie, Irakli Bagration-Mukhraneli, des droits de Youra Bogdanoff au titre de prince serait considérée en elle-même comme une raison juridique suffisante à sa confirmation dans la dignité princière au sein de l'empire de Russie. Un tel document confirmerait en effet du point de vue juridique la dignité princière et fixerait la tradition généalogique familiale de cette famille. C'est pourquoi Igor et Grichka Bogdanoff, ainsi que les enfants légitimes d'Igor, s'octroient le droit d'user aujourd'hui des titres de princes et princesses Bogdanoff (voir Lettre du Dr Stanislaw W. Dumin, président de la Fédération Russe de Généalogie et de la Société d'Histoire et de Généalogie à Moscou, Secrétaire général de l'Académie Internationale de Généalogie, et du prince Vadime Lopoukhine, vice-président de l'Assemblée de la Noblesse Russe : Certificat quant aux droits de Youri Mikhailovitch Bogdanoff et de sa descendance à la dignité et au titre princier. 25 décembre 2001). +
  12. +
  13. ^ "Ancestry of Igor and Grichka Bogdanov". www.wargs.com. +
  14. +
  15. ^ "Igor et Grischka Bogdanoff : le triste destin de leur pèr... - Closer". www.closermag.fr. 24 February 2019. +
  16. +
  17. ^ Maud Guillaumin (2019). Le mystère Bogdanoff. L'Archipel. +
  18. +
  19. ^ Mustafa, Filiz (29 December 2021). "Bogdanoff twins before surgery look explored as Grichka and Igor die at 72". HITC. Retrieved 4 January 2022. +
  20. +
  21. ^ a b c d e f g h i Overbye, Dennis (9 November 2002). "Are They a) Geniuses or b) Jokers?; French Physicists' Cosmic Theory Creates a Big Bang of Its Own". The New York Times. p. B2. +
  22. +
  23. ^ a b c d e f g h Richard Monastersky (5 November 2002). "The Emperor's New Science: French TV Stars Rock the World of Theoretical Physics". The Chronicle of Higher Education. Retrieved 11 January 2021. +
  24. +
  25. ^ Johnson, George (17 November 2002). "Ideas & Trends: In Theory, It's True (Or Not)". The New York Times. p. 4004004. +
  26. +
  27. ^ Schubert, Frank (14 June 2008). "Eine Nullnummer". Spektrum.de. Retrieved 11 January 2021. +
  28. +
  29. ^ a b c "France's Bogdanoff TV twins die of Covid six days apart". bbc.co.uk. 4 January 2022. Retrieved 4 January 2022. +
  30. +
  31. ^ Fossé, David (October 2004). "La mystification Bogdanov" (PDF). Ciel et Espace (in French). pp. 52–55. Retrieved 21 July 2019. +
  32. +
  33. ^ Grichka Bogdanoff (1999). Fluctuations quantiques de la signature de la métrique à l'échelle de Planck (entry in the French academic library directory) (doctorate in mathematics). Supervised by Daniel Sternheimer. University of Burgundy. +
  34. +
  35. ^ "INSPIRE-HEP citation information for Bogdanov papers". INSPIRE-HEP. Retrieved 24 February 2018. +
  36. +
  37. ^ a b c "Publish and perish". The Economist. 16 November 2002. +
  38. +
  39. ^ a b c d Butler, Declan (2002). "Theses spark twin dilemma for physicists". Nature. 420 (5): 5. Bibcode:2002Natur.420Q...5B. doi:10.1038/420005a. PMID 12422173. +
  40. +
  41. ^ Muir, Hazel (16 November 2002). "Twins raise ruckus". New Scientist. p. 6. Retrieved 11 July 2019. +
  42. +
  43. ^ John Baez (24 October 2002). "Physics bitten by reverse Alan Sokal hoax?". Newsgroupsci.physics.research. Usenet: ap7tq6$eme$1@glue.ucr.edu. +
  44. +
  45. ^ Orlowski, Andrew (1 November 2002). "Physics hoaxers discover Quantum Bogosity". The Register. Retrieved 27 February 2018. +
  46. +
  47. ^ a b c Hervé Morin (19 December 2002). "La réputation scientifique contestée des frères Bogdanov". Le Monde (in French). Retrieved 11 January 2021. +
  48. +
  49. ^ a b (in German) Christoph Drösser, Ulrich Schnabel. "Die Märchen der Gebrüder Bogdanov" ("Fairy tales of the Brothers Bogdanov") Die Zeit (2002), issue 46. +
  50. +
  51. ^ a b Arun Bala (2016). Complementarity Beyond Physics: Niels Bohr's Parallels. Palgrave MacMillan. pp. 26–27. +
  52. +
  53. ^ Kuperberg, Greg (1 November 2002). "If not a hoax, it's still an embarrassment". Newsgroupsci.physics.research. Usenet: apu93q$2a2$1@conifold.math.ucdavis.edu. Retrieved 21 July 2019. +
  54. +
  55. ^ a b "Igor and Grichka Bogdanoff, eccentric French TV star twins at the centre of a notorious scientific controversy – obituary". The Daily Telegraph. 4 January 2022. Archived from the original on 12 January 2022. Retrieved 4 January 2022. +
  56. +
  57. ^ France 2 TV talk show, Tout le monde en parle, 12 June 2004. See Riché, Pascal (30 September 2010). "Quand Charpak parlait de son Nobel (et faisait le mariole)". L'Obs (in French). Retrieved 21 November 2018. +
  58. +
  59. ^ "Les frères Bogdanov, la science et les médias". Acrimed (in French). 29 November 2004. Retrieved 11 January 2021. +
  60. +
  61. ^ Oeckl, Robert. "Review of 'Topological field theory of the initial singularity of spacetime'". MathSciNet. MR 1894907. {{cite journal}}: Cite journal requires |journal= (help) +
  62. +
  63. ^ Huet, Sylvestre (15 October 2010). "Un document accablant pour les Bogdanov". Libération (in French). Retrieved 21 July 2019. +
  64. +
  65. ^ "Rapport sur l'article "Topological field theory of the initial singularity of spacetime"" (PDF). Retrieved 21 July 2019. +
  66. +
  67. ^ Parienté, Jonathan (16 October 2010). "Les jumeaux Bogdanov étrillés par le CNRS". En quête de sciences (in French). Le Monde. Retrieved 24 February 2018. +
  68. +
  69. ^ a b "Les Bogdanov réclamaient un million, ils sont condamnés à payer 2000 euros". L'Express (in French). 2 July 2015. Retrieved 25 February 2018. +
  70. +
  71. ^ a b "Les frères Bogdanov condamnés". Ciel et Espace (in French). October 2006. Archived from the original on 17 November 2006. Retrieved 7 October 2006. +
  72. +
  73. ^ a b "Fin du litige avec Ciel et Espace". L'Obs (in French). 14 October 2006. Retrieved 25 February 2018. +
  74. +
  75. ^ a b Huet, Sylvestre (15 March 2012). "Un curieux jugement pour les frères Bogdanov". Libération (in French). Retrieved 12 July 2019. +
  76. +
  77. ^ Foucart, Stéphane (20 April 2012). "Les chercheurs et la menace Bogdanov (Researchers and the Bogdanov threat)". Le Monde (in French). +
  78. +
  79. ^ "Frères Bogdanov : 170 scientifiques réclament le droit de les critiquer" [Bogdanov brothers: 170 scientists claim the right of critique]. Le Nouvel Observateur (in French). 26 April 2012. +
  80. +
  81. ^ Gathié, Nathalie (16 October 2010). "Le vrai visage des Bogdanoff". Marianne (in French). Vol. 74. p. 62. +
  82. +
  83. ^ "Les frères Bogdanov font condamner "Marianne"". Le Point (in French). 21 May 2014. Retrieved 21 July 2019. +
  84. +
  85. ^ Auffret, Simon (27 June 2018). "Igor et Grichka Bogdanov, 40 ans d'affaires et de succès populaires". Le Monde (in French). Retrieved 22 July 2019. +
  86. +
  87. ^ "Prof. Grichka Bogdanoff, PhD & Prof. Igor Bogdanoff, PhD". Megatrend University. Archived from the original on 14 July 2014. Retrieved 27 February 2018. +
  88. +
  89. ^ a b Оташевић, Ана (10 June 2014). Како је Мића ректор постао космолог. politika.rs (in Serbian). Retrieved 27 February 2018. +
  90. +
  91. ^ Robinson, Matt (23 June 2014). "The minister, his mentor and the fight against a suspect system in Serbia". Reuters. Retrieved 27 February 2018. +
  92. +
  93. ^ Subasic, Katarina (26 June 2014). "Bogus academic claims tarnish Serbia's ivory tower". Yahoo! News. Agence France-Presse. Retrieved 27 February 2018. +
  94. +
  95. ^ "France's Bogdanoff TV twins die of Covid six days apart". BBC News. 4 January 2022. Retrieved 27 March 2022. +
  96. +
  97. ^ Robinson, Georgina (21 May 2012). "Who are those jaw-dropping twins?". Sydney Morning Herald. Retrieved 18 September 2021. +
  98. +
  99. ^ Mawad, Dalal; Ataman, Joseph (4 January 2022). "French TV star Igor Bogdanoff dies of Covid, days after twin brother". CNN. Retrieved 4 January 2022. +
  100. +
  101. ^ a b Dailey, Natasha (4 January 2022). "Wall Street Bets mourns loss of crypto-meme-famous Bogdanoff twins, who died of COVID-19". Business Insider. Retrieved 4 January 2022. +
  102. +
  103. ^ Média, Prisma. "Igor Bogdanov, six fois papa". Gala.fr (in French). Retrieved 1 January 2022. +
  104. +
  105. ^ "Igor convole à Chambord". ladepeche.fr (in French). Retrieved 1 January 2022. +
  106. +
  107. ^ "French TV star Igor Bogdanoff dies of Covid, days after twin brother". CNN. 4 January 2022. Retrieved 4 January 2021. [...] they had been at the Georges Pompidou hospital since December 15 [...] +
  108. +
  109. ^ "Grichka Bogdanoff, l'un des jumeaux stars des années 1980, est mort du Covid-19". La Monde. 28 December 2021. Retrieved 28 December 2021. +
  110. +
  111. ^ "Igor Bogdanoff est mort, six jours après son frère jumeau Grichka". L'Obs (in French). Agence France-Presse. 3 January 2022. Retrieved 3 January 2022. +
  112. +
  113. ^ "Grichka Bogdanoff, l'un des jumeaux stars des années 1980, est mort du Covid-19". Le Monde.fr (in French). 28 December 2021. Retrieved 4 January 2022. +
  114. +
  115. ^ "Mort d'Igor Bogdanoff, six jours après son frère Grichka". BFMTV (in French). Retrieved 4 January 2022. +
  116. +
  117. ^ "Les obsèques des frères Bogdanoff célébrées dans l'intimité de l'église de la Madeleine à Paris". Ouest France (in French). 10 January 2022. Retrieved 16 January 2022.. +
  118. +
  119. ^ Alberganti, Michel (27 April 2012). "Les frères Bogdanoff: mentalistes de la science (fiction)". Slate.fr (in French). Retrieved 4 January 2022. +
  120. +
+

Sources[edit]

+
  • Luboš Motl, L'équation Bogdanoff: le secret de l'origine de l'univers?, translated from English by Sonia Quémener, Marc Lenoir and Laurent Martein; Preface by Clóvis de Matos, Presses de la Renaissance, Paris, 2008, 237 pp., ISBN 978-2-7509-0386-2, BNF 411908225
+ + + + + +
+
+ +
+
+ +
+

Navigation menu

+
+ + + + +
+ + + + + + + + +
+
+ + + + + + + + + + + +
+
+ + + + +
+ + + + + + + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/21-wikipedia-bogdanoff-slow.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/21-wikipedia-bogdanoff-slow.wthtml new file mode 100644 index 00000000..9e474667 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/21-wikipedia-bogdanoff-slow.wthtml @@ -0,0 +1,767 @@ +@! { + + + + + Igor and Grichka Bogdanoff - Wikipedia + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+

Igor and Grichka Bogdanoff

+
+
From Wikipedia, the free encyclopedia
+
+
+ +
+ Jump to navigation + Jump to search +
+ +

+

+
Igor and Grichka Bogdanoff
Présentation équipe DMBC, 10 septembre 2016 - 6.jpg
Grichka (left) and Igor (right) in 2016
Born
Igor Youriévitch Bogdanoff
Grégoire Youriévitch Bogdanoff

(1949-08-29)29 August 1949
DiedIgor: 3 January 2022(2022-01-03) (aged 72)
Grichka: 28 December 2021(2021-12-28) (aged 72)
Paris, France
Other names
+
  • Bogdanoff twins
+
OccupationMedia personalities
Known for
Alma materUniversity of Burgundy
Scientific career
FieldsTheoretical physics
ThesisFluctuations quantiques de la signature de la métrique à l'échelle de Planck (1999)
Doctoral advisorMoshé Flato [fr], Daniel Sternheimer
+
+
+

Igor Youriévitch Bogdanoff (French pronunciation: ​[iɡɔʁ juʁi.evitʃ bɔɡdanɔf]; 29 August 1949 – 3 January 2022) and Grégoire "Grichka" Youriévitch Bogdanoff (French: [ɡʁeɡwaʁ ɡʁiʃka]; 29 August 1949 – 28 December 2021) were French twin television presenters,[1] producers, and essayists who, from the 1970s on, presented various subjects in science fiction, popular science, and cosmology. They were involved in a number of controversies, most notably the Bogdanov affair, in which the brothers were alleged to have written nonsensical advanced physics papers that were nonetheless published in reputable scientific journals. +

+ + +

Early years[edit]

+
The twins' maternal grandmother, Berta Kolowrat-Krakowská
+

Igor and Grichka Bogdanoff were identical twin brothers born to Maria "Maya" Dolores Franzyska Kolowrat-Krakowská (1926–1982) and Yuri Mikhaïlovitch Bogdanoff (1928–2012),[2] an itinerant Russian farm worker, later a painter. Igor Bogdanoff was born 40 minutes before Grichka. They had no connection to, or involvement with, their father's family, and were raised by their maternal grandmother, Countess Bertha Kolowrat-Krakowská (1890–1982),[3] in her castle in southern France. Bertha Kolowrat-Krakowská belonged to the noble Kolowrat family of Bohemia and was married to a member of the Austrian princely house of Colloredo-Mannsfeld.[4] Her pregnancy by African-American tenor Roland Hayes caused her to forfeit access to her four elder children, to her palatial homes in Berlin and Prague, and also her reputation in European society.[3] She tried to sustain her episodic relationship with Hayes after her divorce and his return to the United States, but declined his offer to legally adopt and raise their daughter, who became Igor and Grichka's mother.[3] +

Although the Bogdanoff twins claimed to be descended paternally from a noble Muslim Tatar family traceable to the beginning of the 17th century (originally from Penza, one of whose mirzas converted to Orthodox Christianity, and was rewarded with the title of prince by a decree from Tsar Feodor III; the mirza did not exercise this right, and the title of "Prince Bogdanoff" was lost by the end of the 19th century),[5][6] there is scant evidence for that. Genealogist William Addams Reitwiesner observed: "The Bogdanov twins claim that their father was a member of a princely Russian family. Other than a statement by Dr. Stanislaus Dumin (included in a message posted by the twins on 7 Jan 2005 to the alt.talk.royalty Usenet newsgroup), there isn't much evidence to support this claim."[7] The journalist and documentary filmmaker Maud Guillaumin, author of Le mystère Bogdanoff (L'Archipel, 2019), comprehensively examined the twins' account, noting it to comprise "approximations and historical inaccuracies"; she found that Yuri Bogdanoff had gone to Spain as a young man, and, unable to return to the U.S.S.R. because he would have been considered a spy and imprisoned, went to France and began "a life of wandering from farm to Pyrenean farm" before, in 1948 aged 21, arriving at the castle of his future mother-in-law, "renowned in the Gers for employing Slavs". Guillaumin noted that "the twins totally deny this sad odyssey. They explain that they have found proof that their father was the descendant of a prince, the right arm of Tsar Peter the Great", that "according to them, Youra was a young artist [...] he would have followed 'a solid training as a painter as a free auditor at the Beaux-Arts'", and that "it was there, according to the twins, who love romance, that a "famous writer" met in Paris would have introduced Youra to their grandmother". Guillaumin's interview with the Bogdanoff twins' godmother, Monique David, contradicted their romantic account, and established that the twins' mother, Maya, was pregnant with them at the time of her marriage to Yuri Bogdanoff, who Countess Bertha Kolowrat-Krakowská considered an unworthy match for her daughter. She "chased him away", leading him to be absent from his sons' lives until they were ten years old, and subsequently divorced from Maya.[8][9] +

Besides French, they spoke German, Russian, and English. Their grandmother spoke several languages, as well.[10] +

+

Television shows[edit]

+
Igor (left) and Grichka (right) in the 1990s
+

The brothers began careers in television, hosting several popular programs on science and science fiction.[11][12][13] The first of these, Temps X (Time X), ran from 1979 to 1989[12][14] and introduced several British and American science-fiction series to the French public, including The Prisoner, Star Trek, and Doctor Who, in addition to featuring musical guests such as Jean-Michel Jarre.[15] +

In 2002, the Bogdanoffs launched a new weekly television show, Rayons X (X Rays), on the French public channel France 2. In August 2004, they presented a 90-minute special cosmology program.[16] +

+

Academic careers[edit]

+

Grichka Bogdanoff received a Ph.D. degree in mathematics from the University of Burgundy (Dijon) in 1999.[17][11] In 2002, Igor Bogdanoff received a Ph.D. in theoretical physics from the University of Burgundy.[11] Both brothers received the lowest passing grade of "honorable".[11] +

+

Bogdanov affair[edit]

+ +
Grichka (left) and Igor (right) Bogdanoff in 2010
+

In 2001 and 2002, the brothers published five papers (including "Topological field theory of the initial singularity of spacetime") in peer-reviewed physics journals.[18][19] Controversy over the Bogdanoffs' work began on 22 October 2002, with an email sent by University of Tours physicist Max Niedermaier to University of Pittsburgh physicist Ezra T. Newman.[20] Niedermaier suggested that the Bogdanoffs' Ph.D. theses and papers were "spoof[s]", created by throwing together instances of theoretical-physics jargon, including terminology from string theory: "The abstracts are delightfully meaningless combinations of buzzwords ... which apparently have been taken seriously."[20][21] +

Copies of the email reached American mathematical physicist John C. Baez, and on 23 October he created a discussion thread about the Bogdanoffs' work on the Usenet newsgroup sci.physics.research, titled "Physics bitten by reverse Alan Sokal hoax?"[12][22] Baez was comparing the Bogdanoffs' publications to the 1996 Sokal affair, in which physicist Alan Sokal successfully submitted an intentionally nonsensical paper to a cultural studies journal in order to criticize that field's lax standards for discussing science. The Bogdanoffs quickly became a popular discussion topic, with most respondents agreeing that the papers were flawed.[19] +

The story spread in public media, prompting Niedermaier to offer an apology to the Bogdanoffs, admitting that he had not read the papers himself. The Bogdanoffs' background in entertainment lent some plausibility to the idea that they were attempting a deliberate hoax, but Igor Bogdanoff quickly denied the accusation.[11][19] +

In October 2002, the Bogdanoffs released an email containing apparently supportive statements by Laurent Freidel, then a visiting professor at the Perimeter Institute for Theoretical Physics.[12] Soon after, Freidel denied writing any such remarks, telling the press that he had forwarded a message containing that text to a friend.[12] +

The online discussion was quickly followed by media attention. The Register reported on the dispute on 1 November 2002,[23] and stories in The Chronicle of Higher Education,[12] Nature,[20] The New York Times,[11] and other publications appeared soon after.[24][25] These news stories included commentary by physicists. +

One of the scientists who approved Igor Bogdanoff's thesis, Roman Jackiw of the Massachusetts Institute of Technology, spoke to The New York Times reporter Dennis Overbye. Overbye wrote that Jackiw was intrigued by the thesis, although it contained many points he did not understand. Jackiw defended the thesis.[11] In contrast, Ignatios Antoniadis (of the École Polytechnique), who approved Grichka Bogdanoff's thesis, later reversed his judgment of it. Antoniadis told Le Monde: +

+

I had given a favorable opinion for Grichka's defense, based on a rapid and indulgent reading of the thesis text. Alas, I was completely mistaken. The scientific language was just an appearance behind which hid incompetence and ignorance of even basic physics.[24]

+

The journal Classical and Quantum Gravity (CQG) published one of the Bogdanoffs' papers, titled "Topological field theory of the initial singularity of spacetime";[26] Ian Russell, assistant director of its journals division, later issued a statement stating that "we deployed our standard peer-review process on that paper."[12] After the publication of the article and the publicity surrounding the controversy, mathematician Greg Kuperberg posted to Usenet a statement written by the journal's senior publisher, Andrew Wray, and its co-editor, Hermann Nicolai. The statement read, in part, +

+

Regrettably, despite the best efforts, the refereeing process cannot be 100% effective. Thus the paper ... made it through the review process even though, in retrospect, it does not meet the standards expected of articles in this journal... The paper was discussed extensively at the annual Editorial Board meeting ... and there was general agreement that it should not have been published. Since then several steps have been taken to further improve the peer review process in order to improve the quality assessment on articles submitted to the journal and reduce the likelihood that this could happen again.[27]

+

The statement was quoted in The New York Times,[11] The Chronicle of Higher Education,[12] and Nature.[20] Moreover, Die Zeit quoted Nicolai as saying that had the paper reached his desk, he would have immediately rejected it.[25] +

The Chinese Journal of Physics published Igor Bogdanoff's "The KMS state of spacetime at the Planck scale", while Nuovo Cimento published "KMS space-time at the Planck scale". According to physicist Arun Bala, all of these papers "involved purported applications of quantum theory to understand processes at the dawn of the universe", but ultimately turned out to be a "hoax perpetrated on the physics community."[26] +

Not all review evaluations were positive. Eli Hawkins, acting as a referee on behalf of the Journal of Physics A, suggested rejecting one of the Bogdanoffs' papers: "It would take up too much space to enumerate all the mistakes: indeed it is difficult to say where one error ends and the next begins."[28] +

Eventually, the controversy attracted mainstream media attention, opening new avenues for physicists' comments to be disseminated. Le Monde quoted Alain Connes, recipient of the 1982 Fields Medal, as saying, "I didn't need long to convince myself that they're talking about things that they haven't mastered."[24] The New York Times reported that the physicists David Gross, Carlo Rovelli, and Lee Smolin considered the Bogdanoff papers nonsensical.[11] Nobel laureate Georges Charpak later stated on a French talk show that the Bogdanoffs' presence in the scientific community was "nonexistent".[29][30] +

Robert Oeckl's official MathSciNet review of "Topological field theory of the initial singularity of spacetime" states that the paper is "rife with nonsensical or meaningless statements and suffers from a serious lack of coherence", follows up with several examples to illustrate his point, and concludes that the paper "falls short of scientific standards and appears to have no meaningful content."[31] An official report from the Centre national de la recherche scientifique (CNRS), which became public in 2010, concluded that the paper "ne peut en aucune façon être qualifié de contribution scientifique" ("cannot in any way be considered a scientific contribution").[32][33] +

The CNRS report summarized the Bogdanoffs' theses thus: "Ces thèses n’ont pas de valeur scientifique. […] Rarement aura-t-on vu un travail creux habillé avec une telle sophistication" ("These theses have no scientific value. [...] Rarely have we seen a hollow work dressed with such sophistication").[34][35] +

+

Lawsuits[edit]

+

On December 30, 2004, the Bogdanoffs sued Ciel et Espace for defamation over the publication of a critical article titled "The Mystification of the Bogdanoffs".[36] In September 2006, the case was dismissed after the Bogdanoffs missed court deadlines; they were ordered to pay 2,500 to the magazine's publisher to cover its legal costs.[36][37] There was never a substantive ruling on whether or not the Bogdanoffs had been defamed.[37] +

+ Alain Riazuelo, an astrophysicist at the Institut d'Astrophysique de Paris, participated in many of the online discussions of the Bogdanoffs' work. He posted an unpublished version of Grichka Bogdanoff's Ph.D. thesis on his personal website, along with his critical analysis. Bogdanoff subsequently described this version as "dating from 1991 and too unfinished to be made public". Rather than suing Riazuelo for defamation, Bogdanoff filed a criminal complaint of copyright (droit d'auteur) violation against him in May 2011.[38] +

The police detained and interrogated Riazuelo. He was convicted in March 2012. A fine of €2,000 the court imposed was suspended, and only €1.00 of damages was awarded,[38] but in passing judgement the court stated that the scientist had "lacked prudence", given "the fame of the plaintiff".[39] +

The verdict outraged many scientists, who felt that the police and courts should have no say in a discussion of the scientific merits of a piece of work. In April 2012, a group of 170 scientists published an open letter titled L'affaire Bogdanoff: Liberté, Science et Justice, Des scientifiques revendiquent leur droit au blâme (The Bogdanoff Affair: Liberty, Science and Justice, scientists claim their right of critique).[40] +

In 2014, the Bogdanoffs sued the weekly magazine Marianne for defamation, on account of reporting the magazine had published in 2010[41] which had brought the CNRS report to light. The magazine was eventually ordered to pay €64,000 in damages, much less than the €800,000 each which the Bogdanoffs had originally demanded.[42] The Bogdanoffs also sued the CNRS for €1.2 million in damages, claiming that the CNRS report had "porté atteinte à leur honneur, à leur réputation et à leur crédit" ("undermined their honor, reputation and credit") and calling the report committee a "Stasi scientifique", but a tribunal ruled against them in 2015 and ordered them to pay €2,000.[35][43] +

+

Megatrend University[edit]

+

In 2005, the Bogdanoffs became professors at Megatrend University in Belgrade, where they were appointed to Chairs of Cosmology and made directors of the 'Megatrend Laboratory of Cosmology'.[44][45] Mića Jovanović, the rector and owner of Megatrend University, wrote a preface for the Serbian edition of Avant le Big Bang.[45] Jovanović himself later became embroiled in controversy and resigned his post, when he was found out to not have obtained a Ph.D. at the London School of Economics as he had claimed.[46] This scandal, combined with the presence of the Bogdanoffs, contributed to an atmosphere of controversy surrounding Megatrend.[47] +

+

Personal lives[edit]

+

The Bogdanoff twins, who denied having undergone plastic surgery,[48] became known for their prominent cheekbones and chins. In 2010, The Sydney Morning Herald described the twins' cheekbones as "so high and bulbous as to appear to threaten their owners' vision", adding that the twins' appearance at the Cannes Film Festival had "caused a stir around the world". The Herald noted that the twins' cheekbones had become noticeably larger in the 1990s, and that "growth in their lips and chins continued unabated through the last decade".[49] According to former education minister Luc Ferry, a friend of the brothers, they had both received botox injections for cosmetic treatment.[15] +

The twins became popular Internet memes, especially among enthusiasts of cryptocurrency, jokingly depicting the Bogdanoffs as "all-powerful market makers". Their status as "crypto memes" was covered by several outlets upon their deaths, including CNN, Business Insider, and The Daily Telegraph.[28][50][51] The twins "went along with their meme fame", according to Business Insider, and said they predicted cryptocurrency in the 1980s on Temps X.[51] +

Igor Bogdanoff had six children, four from his first marriage and two from his second.[52] He married his second wife, Amélie de Bourbon-Parme, civilly in Paris on 1 October 2009 and religiously in Chambord two days later.[53] +

+

Deaths[edit]

+

The Bogdanoff twins were both hospitalized, at the Georges Pompidou European Hospital in Paris,[54] in critical condition on 15 December 2021, after contracting COVID-19. Grichka died on 28 December,[55] and Igor died six days later, on 3 January 2022.[56] They were 72 and both were unvaccinated.[57][58][15] The funeral for both twins was held on 10 January 2022, in the Church of the Madeleine, in Paris, France.[59] +

+

Publications[edit]

+

The Bogdanoff brothers published a number of works in science fiction, philosophy and popular science. Since 1991, they signed their books as "Bogdanov", preferring "v" to "ff". +

+
  • Clefs pour la science-fiction (essay), Éditions Seghers, 378 p., Paris, 1976[ISBN missing], BNF:34707099q.
  • +
  • L'Effet science-fiction: à la recherche d'une définition (essay), Éditions Robert Laffont, Paris, 1979, 423 p., ISBN 978-2-221-00411-1, BNF:34650185 g.
  • +
  • Chroniques du "Temps X" (preface by Gérard Klein), Éditions du Guépard, Paris, 1981, 247 p., ISBN 978-2-86527-030-9, BNF: 34734883f.
  • +
  • La Machine fantôme, Éditions J'ai lu, 1985, 251 p., ISBN 978-2-277-21921-7, BNF:34842073t.
  • +
  • La Mémoire double (novel), first as hardcover on Éditions Hachette, Paris, 1985, 381 p., ISBN 978-2-01-011494-6, BNF:348362498; then as pocket book
  • +
  • Dieu et la science: vers le métaréalisme (interviews with Jean Guitton): Hardcover Éditions Grasset, Paris, 1991, 195 p., ISBN 978-2-246-42411-6, BNF: 35458968t; then as a pocketbook
  • +
  • Avant le Big Bang: la création du monde (essay), 2004[60]
  • +
  • Voyage vers l'Instant Zéro, Éditions EPA, Paris, 2006, 185 p., ISBN 978-2-85120-635-0, BNF: 40986028h.
  • +
  • Nous ne sommes pas seuls dans l'univers, Éditions EPA, Paris, 2007, 191 p., ISBN 978-2-85120-664-0, BNF: 411885989.
  • +
  • Au commencement du temps, Éditions Flammarion, Paris, 2009, 317 p., ISBN 978-2-08-120832-2, BNF: 420019981.
  • +
  • Le Visage de Dieu, (with a preface by Robert Woodrow Wilson and endnotes by Jim Peebles, Robert Woodrow Wilson and John Mather, Éditions Grasset, Paris, May 2010, 282 p., ISBN 978-2-246-77231-6, BNF: 42207600f.
  • +
  • Le Dernier Jour des dinosaures Éditions de la Martinière, Octobre 2011, ISBN 978-2732447100
  • +
  • La Pensée de Dieu, (with endnotes by Luis Gonzalez-Mestres), Éditions Grasset, Paris, June 2012, ISBN 978-2-246-78509-5
  • +
  • Le mystère du satellite Planck (Qu'y avait-il avant le Big Bang ?) (with preface and endnotes by Luis Gonzalez-Mestres, Éditions Eyrolles, June 2013, ISBN 978-2-212-55732-9
  • +
  • La Fin du hasard, Éditions Grasset, Paris, Octobre 2013, ISBN 978-2-246-80990-6
  • +
  • 3 minutes pour comprendre la grande théorie du Big Bang (preface by John Mather, end notes by Luis Gonzalez-Mestres, Éditions Le Courrier du Livre, October 2014, ISBN 978-2702911211
+

References[edit]

+
+
    +
  1. ^ Luis Gonzalez-Mestres, L'Énigme Bogdanov, Éditions Télémaque, Paris, 2015, 320 p., ISBN 978-2-7533-0266-2 +
  2. +
  3. ^ "Youra Bogdanoff, père des célèbres frères Igor et Grishka Bogdanoff est décédé cette semaine. D'origine russe, il était né le 28 janvier 1928 à Saint-Pétersbourg. Artiste-peintre, il s'était établi à Saint-Lary avec son épouse Maya, avant la naissance de leurs premiers enfants, Igor et Grichka. Les frères Bogdanoff ont quatre frères et sœurs plus jeunes : François, Laurence, Géraldine et Véronique. Un recueillement en sa mémoire aura lieu le mercredi 8 août, à 11 heures, au cimetière de Saint-Lary. La Dépêche du Midi présente ses condoléances à la famille (Youra Bogdanof)" [father of famous brothers Igor and Grishka Bogdanoff died this week. Of Russian origin, he was born on January 28, 1928 in Saint Petersburg. Artist-painter, he had settled in Saint-Lary with his wife Maya, before the birth of their first children, Igor and Grichka. The Bogdanoff brothers have four younger siblings: François, Laurence, Géraldine and Véronique. A meditation in his memory will take place on Wednesday August 8, at 11 a.m., at the Saint-Lary cemetery. La Dépêche du Midi presents its condolences to the family]. www.ladepeche.fr. +
  4. +
  5. ^ a b c Brooks, Christopher A. Roland Hayes: The Legacy of an American Tenor. Indiana University Press. Bloomington. 2015. pp. 358, 361–62, 366–67, 379. ISBN 978-0-253-01536-5. +
  6. +
  7. ^ Genealogisches Handbuch des Adels, Fürstliche Häuser XIX. "Colloredo-Mannsfeld". C.A. Starke Verlag, 2011, pp. 127–29. (German). ISBN 978-3-7980-0849-6. +
  8. +
  9. ^ Après consultation de tous les nobiliaires faisant autorité, aucun ne mentionne une quelconque famille de prince Bogdanoff : Patrick de Gmeline. « Dictionnaire de la noblesse russe ». Éditions Contrepoint, 1978, Almanach de Gotha 1918, Almanach de Gotha 1940, Almanach de Gotha, 2013. +
  10. +
  11. ^ Cependant, cela ne les prive pas théoriquement de la possibilité de confirmer à nouveau leur droit au titre de prince sur les voies de la grâce du chef de la maison impériale de Russie (selon plusieurs exemples connus) : les Bogdanoff sont de nouveau cités comme famille princière en 1906 dans des dictionnaires généalogiques russes. La reconnaissance par le chef de la maison souveraine royale de Georgie, Irakli Bagration-Mukhraneli, des droits de Youra Bogdanoff au titre de prince serait considérée en elle-même comme une raison juridique suffisante à sa confirmation dans la dignité princière au sein de l'empire de Russie. Un tel document confirmerait en effet du point de vue juridique la dignité princière et fixerait la tradition généalogique familiale de cette famille. C'est pourquoi Igor et Grichka Bogdanoff, ainsi que les enfants légitimes d'Igor, s'octroient le droit d'user aujourd'hui des titres de princes et princesses Bogdanoff (voir Lettre du Dr Stanislaw W. Dumin, président de la Fédération Russe de Généalogie et de la Société d'Histoire et de Généalogie à Moscou, Secrétaire général de l'Académie Internationale de Généalogie, et du prince Vadime Lopoukhine, vice-président de l'Assemblée de la Noblesse Russe : Certificat quant aux droits de Youri Mikhailovitch Bogdanoff et de sa descendance à la dignité et au titre princier. 25 décembre 2001). +
  12. +
  13. ^ "Ancestry of Igor and Grichka Bogdanov". www.wargs.com. +
  14. +
  15. ^ "Igor et Grischka Bogdanoff : le triste destin de leur pèr... - Closer". www.closermag.fr. 24 February 2019. +
  16. +
  17. ^ Maud Guillaumin (2019). Le mystère Bogdanoff. L'Archipel. +
  18. +
  19. ^ Mustafa, Filiz (29 December 2021). "Bogdanoff twins before surgery look explored as Grichka and Igor die at 72". HITC. Retrieved 4 January 2022. +
  20. +
  21. ^ a b c d e f g h i Overbye, Dennis (9 November 2002). "Are They a) Geniuses or b) Jokers?; French Physicists' Cosmic Theory Creates a Big Bang of Its Own". The New York Times. p. B2. +
  22. +
  23. ^ a b c d e f g h Richard Monastersky (5 November 2002). "The Emperor's New Science: French TV Stars Rock the World of Theoretical Physics". The Chronicle of Higher Education. Retrieved 11 January 2021. +
  24. +
  25. ^ Johnson, George (17 November 2002). "Ideas & Trends: In Theory, It's True (Or Not)". The New York Times. p. 4004004. +
  26. +
  27. ^ Schubert, Frank (14 June 2008). "Eine Nullnummer". Spektrum.de. Retrieved 11 January 2021. +
  28. +
  29. ^ a b c "France's Bogdanoff TV twins die of Covid six days apart". bbc.co.uk. 4 January 2022. Retrieved 4 January 2022. +
  30. +
  31. ^ Fossé, David (October 2004). "La mystification Bogdanov" (PDF). Ciel et Espace (in French). pp. 52–55. Retrieved 21 July 2019. +
  32. +
  33. ^ Grichka Bogdanoff (1999). Fluctuations quantiques de la signature de la métrique à l'échelle de Planck (entry in the French academic library directory) (doctorate in mathematics). Supervised by Daniel Sternheimer. University of Burgundy. +
  34. +
  35. ^ "INSPIRE-HEP citation information for Bogdanov papers". INSPIRE-HEP. Retrieved 24 February 2018. +
  36. +
  37. ^ a b c "Publish and perish". The Economist. 16 November 2002. +
  38. +
  39. ^ a b c d Butler, Declan (2002). "Theses spark twin dilemma for physicists". Nature. 420 (5): 5. Bibcode:2002Natur.420Q...5B. doi:10.1038/420005a. PMID 12422173. +
  40. +
  41. ^ Muir, Hazel (16 November 2002). "Twins raise ruckus". New Scientist. p. 6. Retrieved 11 July 2019. +
  42. +
  43. ^ John Baez (24 October 2002). "Physics bitten by reverse Alan Sokal hoax?". Newsgroupsci.physics.research. Usenet: ap7tq6$eme$1@glue.ucr.edu. +
  44. +
  45. ^ Orlowski, Andrew (1 November 2002). "Physics hoaxers discover Quantum Bogosity". The Register. Retrieved 27 February 2018. +
  46. +
  47. ^ a b c Hervé Morin (19 December 2002). "La réputation scientifique contestée des frères Bogdanov". Le Monde (in French). Retrieved 11 January 2021. +
  48. +
  49. ^ a b (in German) Christoph Drösser, Ulrich Schnabel. "Die Märchen der Gebrüder Bogdanov" ("Fairy tales of the Brothers Bogdanov") Die Zeit (2002), issue 46. +
  50. +
  51. ^ a b Arun Bala (2016). Complementarity Beyond Physics: Niels Bohr's Parallels. Palgrave MacMillan. pp. 26–27. +
  52. +
  53. ^ Kuperberg, Greg (1 November 2002). "If not a hoax, it's still an embarrassment". Newsgroupsci.physics.research. Usenet: apu93q$2a2$1@conifold.math.ucdavis.edu. Retrieved 21 July 2019. +
  54. +
  55. ^ a b "Igor and Grichka Bogdanoff, eccentric French TV star twins at the centre of a notorious scientific controversy – obituary". The Daily Telegraph. 4 January 2022. Archived from the original on 12 January 2022. Retrieved 4 January 2022. +
  56. +
  57. ^ France 2 TV talk show, Tout le monde en parle, 12 June 2004. See Riché, Pascal (30 September 2010). "Quand Charpak parlait de son Nobel (et faisait le mariole)". L'Obs (in French). Retrieved 21 November 2018. +
  58. +
  59. ^ "Les frères Bogdanov, la science et les médias". Acrimed (in French). 29 November 2004. Retrieved 11 January 2021. +
  60. +
  61. ^ Oeckl, Robert. "Review of 'Topological field theory of the initial singularity of spacetime'". MathSciNet. MR 1894907. {{cite journal}}: Cite journal requires |journal= (help) +
  62. +
  63. ^ Huet, Sylvestre (15 October 2010). "Un document accablant pour les Bogdanov". Libération (in French). Retrieved 21 July 2019. +
  64. +
  65. ^ "Rapport sur l'article "Topological field theory of the initial singularity of spacetime"" (PDF). Retrieved 21 July 2019. +
  66. +
  67. ^ Parienté, Jonathan (16 October 2010). "Les jumeaux Bogdanov étrillés par le CNRS". En quête de sciences (in French). Le Monde. Retrieved 24 February 2018. +
  68. +
  69. ^ a b "Les Bogdanov réclamaient un million, ils sont condamnés à payer 2000 euros". L'Express (in French). 2 July 2015. Retrieved 25 February 2018. +
  70. +
  71. ^ a b "Les frères Bogdanov condamnés". Ciel et Espace (in French). October 2006. Archived from the original on 17 November 2006. Retrieved 7 October 2006. +
  72. +
  73. ^ a b "Fin du litige avec Ciel et Espace". L'Obs (in French). 14 October 2006. Retrieved 25 February 2018. +
  74. +
  75. ^ a b Huet, Sylvestre (15 March 2012). "Un curieux jugement pour les frères Bogdanov". Libération (in French). Retrieved 12 July 2019. +
  76. +
  77. ^ Foucart, Stéphane (20 April 2012). "Les chercheurs et la menace Bogdanov (Researchers and the Bogdanov threat)". Le Monde (in French). +
  78. +
  79. ^ "Frères Bogdanov : 170 scientifiques réclament le droit de les critiquer" [Bogdanov brothers: 170 scientists claim the right of critique]. Le Nouvel Observateur (in French). 26 April 2012. +
  80. +
  81. ^ Gathié, Nathalie (16 October 2010). "Le vrai visage des Bogdanoff". Marianne (in French). Vol. 74. p. 62. +
  82. +
  83. ^ "Les frères Bogdanov font condamner "Marianne"". Le Point (in French). 21 May 2014. Retrieved 21 July 2019. +
  84. +
  85. ^ Auffret, Simon (27 June 2018). "Igor et Grichka Bogdanov, 40 ans d'affaires et de succès populaires". Le Monde (in French). Retrieved 22 July 2019. +
  86. +
  87. ^ "Prof. Grichka Bogdanoff, PhD & Prof. Igor Bogdanoff, PhD". Megatrend University. Archived from the original on 14 July 2014. Retrieved 27 February 2018. +
  88. +
  89. ^ a b Оташевић, Ана (10 June 2014). Како је Мића ректор постао космолог. politika.rs (in Serbian). Retrieved 27 February 2018. +
  90. +
  91. ^ Robinson, Matt (23 June 2014). "The minister, his mentor and the fight against a suspect system in Serbia". Reuters. Retrieved 27 February 2018. +
  92. +
  93. ^ Subasic, Katarina (26 June 2014). "Bogus academic claims tarnish Serbia's ivory tower". Yahoo! News. Agence France-Presse. Retrieved 27 February 2018. +
  94. +
  95. ^ "France's Bogdanoff TV twins die of Covid six days apart". BBC News. 4 January 2022. Retrieved 27 March 2022. +
  96. +
  97. ^ Robinson, Georgina (21 May 2012). "Who are those jaw-dropping twins?". Sydney Morning Herald. Retrieved 18 September 2021. +
  98. +
  99. ^ Mawad, Dalal; Ataman, Joseph (4 January 2022). "French TV star Igor Bogdanoff dies of Covid, days after twin brother". CNN. Retrieved 4 January 2022. +
  100. +
  101. ^ a b Dailey, Natasha (4 January 2022). "Wall Street Bets mourns loss of crypto-meme-famous Bogdanoff twins, who died of COVID-19". Business Insider. Retrieved 4 January 2022. +
  102. +
  103. ^ Média, Prisma. "Igor Bogdanov, six fois papa". Gala.fr (in French). Retrieved 1 January 2022. +
  104. +
  105. ^ "Igor convole à Chambord". ladepeche.fr (in French). Retrieved 1 January 2022. +
  106. +
  107. ^ "French TV star Igor Bogdanoff dies of Covid, days after twin brother". CNN. 4 January 2022. Retrieved 4 January 2021. [...] they had been at the Georges Pompidou hospital since December 15 [...] +
  108. +
  109. ^ "Grichka Bogdanoff, l'un des jumeaux stars des années 1980, est mort du Covid-19". La Monde. 28 December 2021. Retrieved 28 December 2021. +
  110. +
  111. ^ "Igor Bogdanoff est mort, six jours après son frère jumeau Grichka". L'Obs (in French). Agence France-Presse. 3 January 2022. Retrieved 3 January 2022. +
  112. +
  113. ^ "Grichka Bogdanoff, l'un des jumeaux stars des années 1980, est mort du Covid-19". Le Monde.fr (in French). 28 December 2021. Retrieved 4 January 2022. +
  114. +
  115. ^ "Mort d'Igor Bogdanoff, six jours après son frère Grichka". BFMTV (in French). Retrieved 4 January 2022. +
  116. +
  117. ^ "Les obsèques des frères Bogdanoff célébrées dans l'intimité de l'église de la Madeleine à Paris". Ouest France (in French). 10 January 2022. Retrieved 16 January 2022.. +
  118. +
  119. ^ Alberganti, Michel (27 April 2012). "Les frères Bogdanoff: mentalistes de la science (fiction)". Slate.fr (in French). Retrieved 4 January 2022. +
  120. +
+

Sources[edit]

+
  • Luboš Motl, L'équation Bogdanoff: le secret de l'origine de l'univers?, translated from English by Sonia Quémener, Marc Lenoir and Laurent Martein; Preface by Clóvis de Matos, Presses de la Renaissance, Paris, 2008, 237 pp., ISBN 978-2-7509-0386-2, BNF 411908225
+ + + + + +
+
+ +
+
+ +
+

Navigation menu

+
+ + + + +
+ + + + + + + + +
+
+ + + + + + + + + + + +
+
+ + + + +
+ + + + + + + + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/22-jetbrains-youtrack.html b/src/WattleScript.Tests/Templating/Tests/Html/22-jetbrains-youtrack.html new file mode 100644 index 00000000..adb7a7b8 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/22-jetbrains-youtrack.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/22-jetbrains-youtrack.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/22-jetbrains-youtrack.wthtml new file mode 100644 index 00000000..164e7fee --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/22-jetbrains-youtrack.wthtml @@ -0,0 +1,73 @@ +@{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+
+
+ +
+
+ + + + + + + + + + + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/3-checker.html b/src/WattleScript.Tests/Templating/Tests/Html/3-checker.html new file mode 100644 index 00000000..f5992aa5 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/3-checker.html @@ -0,0 +1,131 @@ + + + + Find Unclosed Tags - Unclosed Tag Checker - HTML5 - by Alicia Ramirez + + + + + + + +
+

Closing Tag Checker for HTML5

+ +
+
+

In HTML5, under certain circumstances, some closing tags are optional. If you leave those closing tags out, the W3C validator will not point them out, since they are technically not an error. Some people, though, may want to close all their tags anyway.

+

If you experience any problems, or have any suggestions, let me know.

+

Before you start

+

Make sure your code is valid, or you could get unexpected results. The script assumes you have valid HTML5 code, but would like to make sure you didn't leave any tags, unintentionally, unclosed.

+

Paste your code here:

+

+ + +

+ +
+ + + +
+
+
© 2016
+ + + + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/3-checker.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/3-checker.wthtml new file mode 100644 index 00000000..f5992aa5 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/3-checker.wthtml @@ -0,0 +1,131 @@ + + + + Find Unclosed Tags - Unclosed Tag Checker - HTML5 - by Alicia Ramirez + + + + + + + +
+

Closing Tag Checker for HTML5

+ +
+
+

In HTML5, under certain circumstances, some closing tags are optional. If you leave those closing tags out, the W3C validator will not point them out, since they are technically not an error. Some people, though, may want to close all their tags anyway.

+

If you experience any problems, or have any suggestions, let me know.

+

Before you start

+

Make sure your code is valid, or you could get unexpected results. The script assumes you have valid HTML5 code, but would like to make sure you didn't leave any tags, unintentionally, unclosed.

+

Paste your code here:

+

+ + +

+ +
+ + + +
+
+
© 2016
+ + + + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/4-checker-block.html b/src/WattleScript.Tests/Templating/Tests/Html/4-checker-block.html new file mode 100644 index 00000000..9ab90f85 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/4-checker-block.html @@ -0,0 +1,130 @@ + + + Find Unclosed Tags - Unclosed Tag Checker - HTML5 - by Alicia Ramirez + + + + + + + +
+

Closing Tag Checker for HTML5

+ +
+
+

In HTML5, under certain circumstances, some closing tags are optional. If you leave those closing tags out, the W3C validator will not point them out, since they are technically not an error. Some people, though, may want to close all their tags anyway.

+

If you experience any problems, or have any suggestions, let me know.

+

Before you start

+

Make sure your code is valid, or you could get unexpected results. The script assumes you have valid HTML5 code, but would like to make sure you didn't leave any tags, unintentionally, unclosed.

+

Paste your code here:

+

+ + +

+ +
+ + + +
+
+
© 2016
+ + + + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/4-checker-block.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/4-checker-block.wthtml new file mode 100644 index 00000000..3c8743c8 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/4-checker-block.wthtml @@ -0,0 +1,132 @@ +@{ + + + Find Unclosed Tags - Unclosed Tag Checker - HTML5 - by Alicia Ramirez + + + + + + + +
+

Closing Tag Checker for HTML5

+ +
+
+

In HTML5, under certain circumstances, some closing tags are optional. If you leave those closing tags out, the W3C validator will not point them out, since they are technically not an error. Some people, though, may want to close all their tags anyway.

+

If you experience any problems, or have any suggestions, let me know.

+

Before you start

+

Make sure your code is valid, or you could get unexpected results. The script assumes you have valid HTML5 code, but would like to make sure you didn't leave any tags, unintentionally, unclosed.

+

Paste your code here:

+

+ + +

+ +
+ + + +
+
+
© 2016
+ + + + + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/5-min.html b/src/WattleScript.Tests/Templating/Tests/Html/5-min.html new file mode 100644 index 00000000..d2f60334 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/5-min.html @@ -0,0 +1,7 @@ + + + Find Unclosed Tags - Unclosed Tag Checker - HTML5 - by Alicia Ramirez + + + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/5-min.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/5-min.wthtml new file mode 100644 index 00000000..ee32feca --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/5-min.wthtml @@ -0,0 +1,9 @@ +@{ + + + Find Unclosed Tags - Unclosed Tag Checker - HTML5 - by Alicia Ramirez + + + + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/6-min-2.html b/src/WattleScript.Tests/Templating/Tests/Html/6-min-2.html new file mode 100644 index 00000000..4bf4f23c --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/6-min-2.html @@ -0,0 +1,17 @@ + + + + Find Unclosed Tags - Unclosed Tag Checker - HTML5 - by Alicia Ramirez + + + + + + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/6-min-2.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/6-min-2.wthtml new file mode 100644 index 00000000..7bb5bea3 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/6-min-2.wthtml @@ -0,0 +1,19 @@ +@{ + + + + Find Unclosed Tags - Unclosed Tag Checker - HTML5 - by Alicia Ramirez + + + + + + + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/7-root.html b/src/WattleScript.Tests/Templating/Tests/Html/7-root.html new file mode 100644 index 00000000..075f7fa6 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/7-root.html @@ -0,0 +1 @@ +

t

\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/7-root.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/7-root.wthtml new file mode 100644 index 00000000..a0652282 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/7-root.wthtml @@ -0,0 +1,3 @@ +@{ +

t

+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/8-w3s-block-min.html b/src/WattleScript.Tests/Templating/Tests/Html/8-w3s-block-min.html new file mode 100644 index 00000000..17f353b2 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/8-w3s-block-min.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/8-w3s-block-min.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/8-w3s-block-min.wthtml new file mode 100644 index 00000000..17f353b2 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/8-w3s-block-min.wthtml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/9-w3s-block-svg.html b/src/WattleScript.Tests/Templating/Tests/Html/9-w3s-block-svg.html new file mode 100644 index 00000000..91f85f7f --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/9-w3s-block-svg.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Html/9-w3s-block-svg.wthtml b/src/WattleScript.Tests/Templating/Tests/Html/9-w3s-block-svg.wthtml new file mode 100644 index 00000000..5af75f47 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Html/9-w3s-block-svg.wthtml @@ -0,0 +1,3 @@ +@{ + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/1-class.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/1-class.html new file mode 100644 index 00000000..b6d1e6ce --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/1-class.html @@ -0,0 +1,2 @@ + +
hello
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/1-class.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/1-class.wthtml new file mode 100644 index 00000000..9ddb06f6 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/1-class.wthtml @@ -0,0 +1,9 @@ +@class MyClass { + X = () => { + return "hello" + } +} +@{ + myClass = new MyClass() +} +
@myClass.X()
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/2-class-base.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/2-class-base.html new file mode 100644 index 00000000..fb7bf248 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/2-class-base.html @@ -0,0 +1,3 @@ + + +
hello
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/2-class-base.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/2-class-base.wthtml new file mode 100644 index 00000000..ebe5aa25 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/2-class-base.wthtml @@ -0,0 +1,12 @@ +@class MyClassA { + X = () => { + return "hello" + } +} +@class MyClassB : MyClassA { + +} +@{ + myClass = new MyClassB() +} +
@myClass.X()
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/3-class-mixin.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/3-class-mixin.html new file mode 100644 index 00000000..00705ab1 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/3-class-mixin.html @@ -0,0 +1,5 @@ + + + + +
hello
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/3-class-mixin.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/3-class-mixin.wthtml new file mode 100644 index 00000000..a47f7c2d --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/3-class-mixin.wthtml @@ -0,0 +1,14 @@ +@mixin M1 { } +@mixin M2 {} +@class MyClassA { + X = () => { + return "hello" + } +} +@class MyClassB : MyClassA with M1, M2 { + +} +@{ + myClass = new MyClassB() +} +
@myClass.X()
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/4-class-invalid.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/4-class-invalid.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/4-class-invalid.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/4-class-invalid.wthtml new file mode 100644 index 00000000..1349807d --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Class/4-class-invalid.wthtml @@ -0,0 +1,7 @@ +@class MyClassB :: MyClassA with M1, M2, d { + +} +@{ + myClass = new MyClassB() +} +
@myClass.X()
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Directive/1-directive.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Directive/1-directive.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Directive/1-directive.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Directive/1-directive.wthtml new file mode 100644 index 00000000..cfd51051 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Directive/1-directive.wthtml @@ -0,0 +1 @@ +@using myLib.somethingElse \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Directive/2-directive-combined.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Directive/2-directive-combined.html new file mode 100644 index 00000000..5f6e84cc --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Directive/2-directive-combined.html @@ -0,0 +1,2 @@ + +100 \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Directive/2-directive-combined.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Directive/2-directive-combined.wthtml new file mode 100644 index 00000000..bc0f97fe --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Directive/2-directive-combined.wthtml @@ -0,0 +1,5 @@ +@using myLib.somethingElse +@{ + x = 100 +} +@x \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/1-enum.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/1-enum.html new file mode 100644 index 00000000..00132a70 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/1-enum.html @@ -0,0 +1 @@ +
Color 1
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/1-enum.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/1-enum.wthtml new file mode 100644 index 00000000..b5ab10f1 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/1-enum.wthtml @@ -0,0 +1,6 @@ +@enum Colors { + Red, + Green, + Blue +} +
Color @Colors.Green
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/2-enum-invalid.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/2-enum-invalid.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/2-enum-invalid.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/2-enum-invalid.wthtml new file mode 100644 index 00000000..7ee2cbb9 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/2-enum-invalid.wthtml @@ -0,0 +1,6 @@ +@enum { + Red, + Green, + Blue +} +
Color @Colors.Green
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/3-enum-invalid-invalid-ident.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/3-enum-invalid-invalid-ident.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/3-enum-invalid-invalid-ident.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/3-enum-invalid-invalid-ident.wthtml new file mode 100644 index 00000000..7fa36d53 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/3-enum-invalid-invalid-ident.wthtml @@ -0,0 +1,6 @@ +@enum 0 { + Red, + Green, + Blue +} +
Color @Colors.Green
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/4-enum-invalid-missing-closing-brk.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/4-enum-invalid-missing-closing-brk.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/4-enum-invalid-missing-closing-brk.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/4-enum-invalid-missing-closing-brk.wthtml new file mode 100644 index 00000000..9dd5476a --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Enum/4-enum-invalid-missing-closing-brk.wthtml @@ -0,0 +1,6 @@ +@enum E { + Red, + Green, + Blue + +
Color @Colors.Green
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/For/1-for.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/For/1-for.html new file mode 100644 index 00000000..66d0d094 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/For/1-for.html @@ -0,0 +1 @@ +
1
2
3
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/For/1-for.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/For/1-for.wthtml new file mode 100644 index 00000000..22173ffc --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/For/1-for.wthtml @@ -0,0 +1,3 @@ +@for (i in 1..3) { +
@i
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/For/2-for-ul.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/For/2-for-ul.html new file mode 100644 index 00000000..081ed02a --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/For/2-for-ul.html @@ -0,0 +1,6 @@ +
    + +
  • 1
  • +
  • 2
  • +
  • 3
  • +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/For/2-for-ul.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/For/2-for-ul.wthtml new file mode 100644 index 00000000..8d41f3ce --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/For/2-for-ul.wthtml @@ -0,0 +1,5 @@ +
    + @for (i in 1..3) { +
  • @i
  • + } +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/1-function.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/1-function.html new file mode 100644 index 00000000..f9c76690 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/1-function.html @@ -0,0 +1,3 @@ + + +
10
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/1-function.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/1-function.wthtml new file mode 100644 index 00000000..662aa3e7 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/1-function.wthtml @@ -0,0 +1,5 @@ +@function MyFunc(n) { +
@n
+} + +@MyFunc(10) \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/2-function-comment.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/2-function-comment.html new file mode 100644 index 00000000..f9c76690 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/2-function-comment.html @@ -0,0 +1,3 @@ + + +
10
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/2-function-comment.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/2-function-comment.wthtml new file mode 100644 index 00000000..fc705ea5 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/2-function-comment.wthtml @@ -0,0 +1,5 @@ +@function @* server comment *@ MyFunc(n) { +
@n
+} + +@MyFunc(10) \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/3-function-annotation.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/3-function-annotation.html new file mode 100644 index 00000000..f9c76690 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/3-function-annotation.html @@ -0,0 +1,3 @@ + + +
10
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/3-function-annotation.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/3-function-annotation.wthtml new file mode 100644 index 00000000..77a7f577 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/Function/3-function-annotation.wthtml @@ -0,0 +1,8 @@ +@{ + @bind('myText') + function MyFunc(n) { +
@n
+ } +} + +@MyFunc(10) \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/1-if.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/1-if.html new file mode 100644 index 00000000..a8ea4b8d --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/1-if.html @@ -0,0 +1 @@ +
10
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/1-if.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/1-if.wthtml new file mode 100644 index 00000000..bbb3b6c9 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/1-if.wthtml @@ -0,0 +1,3 @@ +@if (2 > 1) { +
10
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/10-if-elseif-multiple.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/10-if-elseif-multiple.html new file mode 100644 index 00000000..029f5618 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/10-if-elseif-multiple.html @@ -0,0 +1,2 @@ + +
4
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/10-if-elseif-multiple.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/10-if-elseif-multiple.wthtml new file mode 100644 index 00000000..b31464f8 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/10-if-elseif-multiple.wthtml @@ -0,0 +1,12 @@ +@if (1 > 2) { +
10
+} +else if (2 > 2) { +
5
+} +else if (3 > 2) { +
4
+} +else { +
1
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/11-if-elseif-no-whitespace.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/11-if-elseif-no-whitespace.html new file mode 100644 index 00000000..38e65812 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/11-if-elseif-no-whitespace.html @@ -0,0 +1,2 @@ + +
5
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/11-if-elseif-no-whitespace.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/11-if-elseif-no-whitespace.wthtml new file mode 100644 index 00000000..0e4734fb --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/11-if-elseif-no-whitespace.wthtml @@ -0,0 +1,9 @@ +@if (1 > 2) { +
10
+} +elseif (3 > 2) { +
5
+} +else { +
1
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/12-self-closing.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/12-self-closing.html new file mode 100644 index 00000000..8793df21 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/12-self-closing.html @@ -0,0 +1,4 @@ +
+
+
+
100
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/12-self-closing.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/12-self-closing.wthtml new file mode 100644 index 00000000..380eb4b0 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/12-self-closing.wthtml @@ -0,0 +1,7 @@ +@if (3 > 2) { +
+
+
+ x = 100 +
@x
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/13-transition-in-tag.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/13-transition-in-tag.html new file mode 100644 index 00000000..a97caafa --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/13-transition-in-tag.html @@ -0,0 +1,4 @@ +
+ + 300 +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/13-transition-in-tag.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/13-transition-in-tag.wthtml new file mode 100644 index 00000000..00c19b1b --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/13-transition-in-tag.wthtml @@ -0,0 +1,6 @@ +@if (3 > 2) { +
+ @* server comment *@ + @(100 + 200) +
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/14-transition-in-line.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/14-transition-in-line.html new file mode 100644 index 00000000..8e27be7d --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/14-transition-in-line.html @@ -0,0 +1 @@ +text diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/14-transition-in-line.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/14-transition-in-line.wthtml new file mode 100644 index 00000000..3f32aa39 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/14-transition-in-line.wthtml @@ -0,0 +1,3 @@ +@if (3 > 2) { + @:text +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/15-transition-in-line-2.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/15-transition-in-line-2.html new file mode 100644 index 00000000..1adf42e1 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/15-transition-in-line-2.html @@ -0,0 +1 @@ +text 100 diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/15-transition-in-line-2.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/15-transition-in-line-2.wthtml new file mode 100644 index 00000000..595b6fc1 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/15-transition-in-line-2.wthtml @@ -0,0 +1,6 @@ +@{ + x = 100 +} +@if (3 > 2) { + @:text @x +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/16-transition-text.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/16-transition-text.html new file mode 100644 index 00000000..14063c9d --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/16-transition-text.html @@ -0,0 +1 @@ +Value of a is 10 \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/16-transition-text.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/16-transition-text.wthtml new file mode 100644 index 00000000..fad0fd67 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/16-transition-text.wthtml @@ -0,0 +1,4 @@ +@{ + a = 10 + Value of a is @a +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/2-if-else.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/2-if-else.html new file mode 100644 index 00000000..38e65812 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/2-if-else.html @@ -0,0 +1,2 @@ + +
5
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/2-if-else.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/2-if-else.wthtml new file mode 100644 index 00000000..82697417 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/2-if-else.wthtml @@ -0,0 +1,6 @@ +@if (1 > 2) { +
10
+} +else { +
5
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/3-if-html.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/3-if-html.html new file mode 100644 index 00000000..c2c7f798 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/3-if-html.html @@ -0,0 +1,3 @@ +
+ 10 +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/3-if-html.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/3-if-html.wthtml new file mode 100644 index 00000000..13995964 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/3-if-html.wthtml @@ -0,0 +1,5 @@ +@if (2 > 1) { +
+ 10 +
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/4-if-html-self-closing.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/4-if-html-self-closing.html new file mode 100644 index 00000000..2c294a62 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/4-if-html-self-closing.html @@ -0,0 +1,5 @@ +
+ 10 + + 20 +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/4-if-html-self-closing.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/4-if-html-self-closing.wthtml new file mode 100644 index 00000000..d35c6d1f --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/4-if-html-self-closing.wthtml @@ -0,0 +1,7 @@ +@if (2 > 1) { +
+ 10 + + 20 +
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/5-if-html-deep-nested.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/5-if-html-deep-nested.html new file mode 100644 index 00000000..17035366 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/5-if-html-deep-nested.html @@ -0,0 +1,10 @@ +
+
+
+ +
1
+
2
+
+
+
+
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/5-if-html-deep-nested.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/5-if-html-deep-nested.wthtml new file mode 100644 index 00000000..3c8b8542 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/5-if-html-deep-nested.wthtml @@ -0,0 +1,12 @@ +@if (2 > 1) { +
+
+
+ +
1
+
2
+
+
+
+
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/6-if-html-code-block.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/6-if-html-code-block.html new file mode 100644 index 00000000..b34f34eb --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/6-if-html-code-block.html @@ -0,0 +1,4 @@ +
+ +
2
+
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/6-if-html-code-block.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/6-if-html-code-block.wthtml new file mode 100644 index 00000000..efc94cdc --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/6-if-html-code-block.wthtml @@ -0,0 +1,10 @@ +@if (2 > 1) { +
+ @if (3 > 10) { +
1
+ } + else { +
2
+ } +
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/7-if-block.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/7-if-block.html new file mode 100644 index 00000000..fd0f8821 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/7-if-block.html @@ -0,0 +1,4 @@ +
    + +
  • 20
  • +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/7-if-block.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/7-if-block.wthtml new file mode 100644 index 00000000..6d67d252 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/7-if-block.wthtml @@ -0,0 +1,8 @@ +@{ + x = 20 +} +
    +@if (x > 2) { +
  • @x
  • +} +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/8-if-html-code-block-explicit.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/8-if-html-code-block-explicit.html new file mode 100644 index 00000000..b34f34eb --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/8-if-html-code-block-explicit.html @@ -0,0 +1,4 @@ +
+ +
2
+
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/8-if-html-code-block-explicit.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/8-if-html-code-block-explicit.wthtml new file mode 100644 index 00000000..b6e9b548 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/8-if-html-code-block-explicit.wthtml @@ -0,0 +1,10 @@ +@if (2 > 1) { +
+ @if (3 > 10) { +
@(1)
+ } + else { +
@(2)
+ } +
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/9-if-elseif.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/9-if-elseif.html new file mode 100644 index 00000000..38e65812 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/9-if-elseif.html @@ -0,0 +1,2 @@ + +
5
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/9-if-elseif.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/9-if-elseif.wthtml new file mode 100644 index 00000000..845fe5cc --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/9-if-elseif.wthtml @@ -0,0 +1,9 @@ +@if (1 > 2) { +
10
+} +else if (3 > 2) { +
5
+} +else { +
1
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/1-if.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/1-if.html new file mode 100644 index 00000000..a8ea4b8d --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/1-if.html @@ -0,0 +1 @@ +
10
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/1-if.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/1-if.wthtml new file mode 100644 index 00000000..b01176bd --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/1-if.wthtml @@ -0,0 +1,3 @@ +@if (2 > 1) +
10
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/2-if-missing-expr.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/2-if-missing-expr.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/2-if-missing-expr.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/2-if-missing-expr.wthtml new file mode 100644 index 00000000..1a76b3ad --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/2-if-missing-expr.wthtml @@ -0,0 +1,3 @@ +@if { +
10
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/3-if-missing-expr.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/3-if-missing-expr.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/3-if-missing-expr.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/3-if-missing-expr.wthtml new file mode 100644 index 00000000..20f7e268 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/3-if-missing-expr.wthtml @@ -0,0 +1,4 @@ +@ +@if { +
10
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/4-if-missing-expr.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/4-if-missing-expr.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/4-if-missing-expr.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/4-if-missing-expr.wthtml new file mode 100644 index 00000000..1c9a49ef --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/4-if-missing-expr.wthtml @@ -0,0 +1,6 @@ +@{ + x = 9 +} +@if { +
10
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/5-if-missing-expr.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/5-if-missing-expr.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/5-if-missing-expr.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/5-if-missing-expr.wthtml new file mode 100644 index 00000000..78df982c --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/5-if-missing-expr.wthtml @@ -0,0 +1,6 @@ +@{ + x = 9 +} +@if (```) { +
10
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/6-if-comment.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/6-if-comment.html new file mode 100644 index 00000000..e69de29b diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/6-if-comment.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/6-if-comment.wthtml new file mode 100644 index 00000000..f035f9bd --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/AllowedKeyword/IfElseElseif/Invalid/6-if-comment.wthtml @@ -0,0 +1,3 @@ +@if ( + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/13-function-call-html-nested-escape-comment.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/13-function-call-html-nested-escape-comment.wthtml new file mode 100644 index 00000000..47d9566b --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/13-function-call-html-nested-escape-comment.wthtml @@ -0,0 +1,12 @@ +@{ + say = (what) => { + x = ')/**/\'' + /*comment*/ +
+
@what
+ @x + +
+ } +} +@say("hello") \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/2-simple-newline.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/2-simple-newline.html new file mode 100644 index 00000000..77d09894 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/2-simple-newline.html @@ -0,0 +1,3 @@ +
+ 10 +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/2-simple-newline.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/2-simple-newline.wthtml new file mode 100644 index 00000000..3e8dd8c9 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/2-simple-newline.wthtml @@ -0,0 +1,6 @@ +@{ + x = 10 +} +
+ @x +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/3-simple-table.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/3-simple-table.html new file mode 100644 index 00000000..af507e77 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/3-simple-table.html @@ -0,0 +1 @@ +
hello world
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/3-simple-table.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/3-simple-table.wthtml new file mode 100644 index 00000000..c2b9946e --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/3-simple-table.wthtml @@ -0,0 +1,4 @@ +@{ + tbl = ["hello world"] +} +
@tbl[0]
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/4-nested-table.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/4-nested-table.html new file mode 100644 index 00000000..af507e77 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/4-nested-table.html @@ -0,0 +1 @@ +
hello world
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/4-nested-table.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/4-nested-table.wthtml new file mode 100644 index 00000000..cb0ba923 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/4-nested-table.wthtml @@ -0,0 +1,4 @@ +@{ + tbl = [ ["hello world"] ] +} +
@tbl[0][0]
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/5-call.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/5-call.html new file mode 100644 index 00000000..a8ea4b8d --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/5-call.html @@ -0,0 +1 @@ +
10
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/5-call.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/5-call.wthtml new file mode 100644 index 00000000..5f4ae3a6 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/5-call.wthtml @@ -0,0 +1,10 @@ +@{ + acc = { + myTbl: [10] + } + + fn = () => { + return [[acc]] + } +} +
@fn(((("param"))), [1, 2, acc.myTbl[0]])[0][0].myTbl[0]
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/6-single-dot.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/6-single-dot.html new file mode 100644 index 00000000..5f6a0b25 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/6-single-dot.html @@ -0,0 +1 @@ +
10.
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/6-single-dot.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/6-single-dot.wthtml new file mode 100644 index 00000000..c1fa2b2f --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/6-single-dot.wthtml @@ -0,0 +1,4 @@ +@{ + x = 10 +} +
@x.
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/7-single-dot-eof.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/7-single-dot-eof.html new file mode 100644 index 00000000..52ce0fc3 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/7-single-dot-eof.html @@ -0,0 +1 @@ +
5. \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/7-single-dot-eof.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/7-single-dot-eof.wthtml new file mode 100644 index 00000000..d6411bd3 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/7-single-dot-eof.wthtml @@ -0,0 +1,4 @@ +@{ + x = 5 +} +
@x. \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/8-multiple-dots.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/8-multiple-dots.html new file mode 100644 index 00000000..d6eda7ac --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/8-multiple-dots.html @@ -0,0 +1 @@ +
5... \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/8-multiple-dots.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/8-multiple-dots.wthtml new file mode 100644 index 00000000..47aeacb0 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/8-multiple-dots.wthtml @@ -0,0 +1,4 @@ +@{ + x = 5 +} +
@x... \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/9-function-call.html b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/9-function-call.html new file mode 100644 index 00000000..af507e77 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/9-function-call.html @@ -0,0 +1 @@ +
hello world
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/9-function-call.wthtml b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/9-function-call.wthtml new file mode 100644 index 00000000..0fd458ec --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/ImplicitExpr/Literal/9-function-call.wthtml @@ -0,0 +1,6 @@ +@{ + myFn = () => { + return "hello world" + } +} +
@myFn()
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Invalid/1-unclosed-end.html b/src/WattleScript.Tests/Templating/Tests/Invalid/1-unclosed-end.html new file mode 100644 index 00000000..1c8a701b --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Invalid/1-unclosed-end.html @@ -0,0 +1 @@ +

text \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Invalid/1-unclosed-end.wthtml b/src/WattleScript.Tests/Templating/Tests/Invalid/1-unclosed-end.wthtml new file mode 100644 index 00000000..de2a3503 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Invalid/1-unclosed-end.wthtml @@ -0,0 +1,3 @@ +@{ +

text +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Lua/1-simple.html b/src/WattleScript.Tests/Templating/Tests/Lua/1-simple.html new file mode 100644 index 00000000..105d7d9a --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Lua/1-simple.html @@ -0,0 +1 @@ +100 \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Lua/1-simple.wthtml b/src/WattleScript.Tests/Templating/Tests/Lua/1-simple.wthtml new file mode 100644 index 00000000..4c522b61 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Lua/1-simple.wthtml @@ -0,0 +1,7 @@ +@{ + x = 0 + if 10 > 2 then + x = 100 + end +} +@x \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Lua/2-if.html b/src/WattleScript.Tests/Templating/Tests/Lua/2-if.html new file mode 100644 index 00000000..8115cbb0 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Lua/2-if.html @@ -0,0 +1 @@ +

10
diff --git a/src/WattleScript.Tests/Templating/Tests/Lua/2-if.wthtml b/src/WattleScript.Tests/Templating/Tests/Lua/2-if.wthtml new file mode 100644 index 00000000..2482b87c --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Lua/2-if.wthtml @@ -0,0 +1,5 @@ +@{ + x = 10 +} +@{if x > 2 then }
@x
+@{ end } \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Lua/3-if-no-space.html b/src/WattleScript.Tests/Templating/Tests/Lua/3-if-no-space.html new file mode 100644 index 00000000..a8ea4b8d --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Lua/3-if-no-space.html @@ -0,0 +1 @@ +
10
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Lua/3-if-no-space.wthtml b/src/WattleScript.Tests/Templating/Tests/Lua/3-if-no-space.wthtml new file mode 100644 index 00000000..61ca63cf --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Lua/3-if-no-space.wthtml @@ -0,0 +1,4 @@ +@{ + x = 10 +} +@{if x > 2 then }
@x
@{ end } \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Nodes/1-simple.html b/src/WattleScript.Tests/Templating/Tests/Nodes/1-simple.html new file mode 100644 index 00000000..6d580eca --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Nodes/1-simple.html @@ -0,0 +1,9 @@ + + + + +

My First Heading

+

My first paragraph.

+ + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Nodes/1-simple.wthtml b/src/WattleScript.Tests/Templating/Tests/Nodes/1-simple.wthtml new file mode 100644 index 00000000..6d580eca --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Nodes/1-simple.wthtml @@ -0,0 +1,9 @@ + + + + +

My First Heading

+

My first paragraph.

+ + + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/RawTextElements/1-simple.html b/src/WattleScript.Tests/Templating/Tests/RawTextElements/1-simple.html new file mode 100644 index 00000000..8c8b054c --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/RawTextElements/1-simple.html @@ -0,0 +1,5 @@ +
+ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/RawTextElements/1-simple.wthtml b/src/WattleScript.Tests/Templating/Tests/RawTextElements/1-simple.wthtml new file mode 100644 index 00000000..90073e70 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/RawTextElements/1-simple.wthtml @@ -0,0 +1,7 @@ +@{ +
+ +
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Recovery/1-simple.html b/src/WattleScript.Tests/Templating/Tests/Recovery/1-simple.html new file mode 100644 index 00000000..d21be282 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Recovery/1-simple.html @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Recovery/1-simple.wthtml b/src/WattleScript.Tests/Templating/Tests/Recovery/1-simple.wthtml new file mode 100644 index 00000000..2b1387c9 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Recovery/1-simple.wthtml @@ -0,0 +1,6 @@ +@{ + +} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Recovery/2-table.html b/src/WattleScript.Tests/Templating/Tests/Recovery/2-table.html new file mode 100644 index 00000000..7f887225 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Recovery/2-table.html @@ -0,0 +1,12 @@ + + + + +
37547 TEE Electric Powered Rail Car Train Functions (Abbreviated) +
Function Control Unit Central Station +
Headlights ✔ +
Interior Lights ✔ +
Electric locomotive operating sounds ✔ +
Engineer’s cab lighting ✔ +
Station Announcements - Swiss ✔ +
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Recovery/2-table.wthtml b/src/WattleScript.Tests/Templating/Tests/Recovery/2-table.wthtml new file mode 100644 index 00000000..d5119dfa --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Recovery/2-table.wthtml @@ -0,0 +1,14 @@ +@{ + + + + +
37547 TEE Electric Powered Rail Car Train Functions (Abbreviated) +
Function Control Unit Central Station +
Headlights ✔ +
Interior Lights ✔ +
Electric locomotive operating sounds ✔ +
Engineer’s cab lighting ✔ +
Station Announcements - Swiss ✔ +
+} \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Recovery/3-unclosed-el.html b/src/WattleScript.Tests/Templating/Tests/Recovery/3-unclosed-el.html new file mode 100644 index 00000000..c408eb83 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Recovery/3-unclosed-el.html @@ -0,0 +1 @@ +content
\ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Recovery/4-server-side-tag-name.wthtml b/src/WattleScript.Tests/Templating/Tests/Recovery/4-server-side-tag-name.wthtml new file mode 100644 index 00000000..c3068721 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Recovery/4-server-side-tag-name.wthtml @@ -0,0 +1,2 @@ +@#define TAG "div" +<@TAG>content \ No newline at end of file diff --git a/src/WattleScript.Tests/Templating/Tests/Recovery/5-comment-server.html b/src/WattleScript.Tests/Templating/Tests/Recovery/5-comment-server.html new file mode 100644 index 00000000..a1a27371 --- /dev/null +++ b/src/WattleScript.Tests/Templating/Tests/Recovery/5-comment-server.html @@ -0,0 +1 @@ +