tlang-interperter-cs/tlanglib/TLangTemplateEngine.cs

170 lines
4.9 KiB
C#
Raw Normal View History

2023-06-08 18:14:35 +00:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace tlang {
public class TLangGenerator
{
Lazy<(List<LexToken> Tokens,string Source)> srcCode;
public TLangGenerator(string src)
{
srcCode=new Lazy<(List<LexToken> Tokens,string Source)>(()=>{
string text = Lex(src);
Lexer lexer=new Lexer(new StringReader(text));
return (lexer.Tokens,text);
});
}
public string SourceCode
{
get => srcCode.Value.Source;
}
public string Execute(Action<RootEnvironment> parser)
{
Parser p = new Parser(srcCode.Value.Tokens);
RootEnvironment env=new RootEnvironment();
p.LoadEnvironment(env);
StringBuilder builder=new StringBuilder();
env.SetVariable("__writer",new TExternalMethod((args)=>{
if(args.Length >= 1)
{
foreach(var arg in args)
{
builder.Append(arg.ToString());
}
}
return TObject.Null;
}));
parser?.Invoke(env);
p.Execute(env);
//
return builder.ToString();
}
private string Lex(string text)
{
StringBuilder tlangFile = new StringBuilder();
StringBuilder b=new StringBuilder();
bool lastInCode=true;
bool inCode=false;
int i = 0;
bool isDone = false;
Action<int> appendChar = (c)=>{
if((lastInCode != inCode || isDone) && b.Length > 0)
{
if(inCode ^ (isDone && !inCode))
{
tlangFile.Append("__writer(\"");
b.Replace("\n","\\n").Replace("\t","\\t").Replace("\r","\\r").Replace("\"","\\\"").Replace("\'","\\\'");
foreach(var _c in b.ToString())
{
if(_c < 32 || _c > 126)
{
tlangFile.Append($"\\x{((int)_c).ToString("X2")}");
}else{
tlangFile.Append(_c);
}
}
b.Clear();
tlangFile.Append("\");");
}
if(!inCode ^ (isDone && inCode))
{
if(b.Length > 0)
{
tlangFile.Append(b);
}
b.Clear();
}
}
if(c != -1)
{
b.Append((char)c);
}
lastInCode = inCode;
};
bool escapedByAt = false;
while(i < text.Length)
{
char curChar = text[i++];
int nextChar = i<text.Length ? text[i] : -1;
switch(curChar)
{
case '@':
if(nextChar == '{')
{
appendChar('{');
i++;
}else if(nextChar == '}') {
appendChar('}');
i++;
}else if(nextChar == '@')
{
appendChar('@');
i++;
}else{
if(!escapedByAt)
{
inCode=true;
escapedByAt=true;
//we are a variable
foreach(var c in "__writer(")
appendChar(c);
}else
if(escapedByAt)
{
appendChar(')');
appendChar(';');
inCode = false;
escapedByAt = false;
}
}
break;
case '{':
if(nextChar == '{')
{
i++;
inCode = !inCode;
}else{
appendChar(curChar);
}
break;
case '}':
if(nextChar == '}')
{
i++;
inCode = !inCode;
}else{
appendChar(curChar);
}
break;
default:
appendChar(curChar);
break;
}
}
isDone=true;
appendChar(-1);
return tlangFile.ToString();
}
}
}