tlang-runtime-compiler/TLang.Parser/Class1.cs

654 lines
26 KiB
C#
Raw Normal View History

2023-07-27 03:31:32 +00:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using TLang.Lexer;
namespace TLang.Parser
{
public class Parse
{
private Parse(LexContext ctx)
{
Context = ctx;
}
private LexContext Context {get;set;}
private Node Node {get;set;}
private void ParseNodeRoot()
{
Node = ParseNode(true);
}
public static Node ParseFromLexContext(params LexContext[] ctx)
{
if(ctx.Length > 0)
{
var ctx2 = ctx[0];
for(int i = 1;i<ctx.Length;i++)
{
ctx2 += ctx[i];
}
Parse p=new Parse(ctx2);
p.ParseNodeRoot();
return p.Node;
}
return new Node();
}
public static Node ParseFromTextReader(TextReader reader,string filename="memory.tlang")
{
var lexed = Lex.GetTokens(reader,filename);
return ParseFromLexContext(lexed);
}
public static Node ParseFromFiles(params string[] filenames)
{
return ParseFromLexContext(filenames.Select<string,LexContext>(e=>Lex.GetTokensFromFile(e)).ToArray());
}
public static Node ParseFromString(string str,string filename="memory.tlang")
{
var lexed=Lex.GetTokensFromString(str,filename);
return ParseFromLexContext(lexed);
}
private Node ParseNode(bool isRoot=false,bool inCase=false)
{
ScopeNode node = new ScopeNode();
node.LineInfo = Context.CurrentLineInfo;
while(Context.Offset < Context.Tokens.Count && (isRoot || !Context.NextEntries(true,"}").Success))
{
if(Context.NextEntries(true,"{").Success)
{
node.Add(ParseNode());
}
node.Add(ParseAssigable());
}
return node;
}
private Node ParseAssigable()
{
Node expr = ParseLOr();
while(Context.NextEntryIsAnyOf(true,out var token,"=","+=","-=","*=","/=","%=","|=","&=","^=","^^="))
{
if(token.Text == "=")
{
var symbolNode = expr as SymbolNode;
if(symbolNode == null) throw new CompilerError("Assigning variable to something that is not a symbol",expr);
expr = new SetVariableNode(symbolNode.Name,ParseLOr()){LineInfo=token.Position};
}
if(token.Text == "+=")
{
var symbolNode = expr as SymbolNode;
if(symbolNode == null) throw new CompilerError("Assigning variable to something that is not a symbol",expr);
expr = new SetVariableNode(symbolNode.Name,new AddNode(new GetVariableNode(symbolNode.Name),ParseLOr())){LineInfo=token.Position};
}
if(token.Text == "-=")
{
var symbolNode = expr as SymbolNode;
if(symbolNode == null) throw new CompilerError("Assigning variable to something that is not a symbol",expr);
expr = new SetVariableNode(symbolNode.Name,new SubtractNode(new GetVariableNode(symbolNode.Name),ParseLOr())){LineInfo=token.Position};
}
if(token.Text == "*=")
{
var symbolNode = expr as SymbolNode;
if(symbolNode == null) throw new CompilerError("Assigning variable to something that is not a symbol",expr);
expr = new SetVariableNode(symbolNode.Name,new MultiplyNode(new GetVariableNode(symbolNode.Name),ParseLOr())){LineInfo=token.Position};
}
if(token.Text == "/=")
{
var symbolNode = expr as SymbolNode;
if(symbolNode == null) throw new CompilerError("Assigning variable to something that is not a symbol",expr);
expr = new SetVariableNode(symbolNode.Name,new DivideNode(new GetVariableNode(symbolNode.Name),ParseLOr())){LineInfo=token.Position};
}
if(token.Text == "%=")
{
var symbolNode = expr as SymbolNode;
if(symbolNode == null) throw new CompilerError("Assigning variable to something that is not a symbol",expr);
expr = new SetVariableNode(symbolNode.Name,new ModuloNode(new GetVariableNode(symbolNode.Name),ParseLOr())){LineInfo=token.Position};
}
if(token.Text == "|=")
{
var symbolNode = expr as SymbolNode;
if(symbolNode == null) throw new CompilerError("Assigning variable to something that is not a symbol",expr);
expr = new SetVariableNode(symbolNode.Name,new BOrNode(new GetVariableNode(symbolNode.Name),ParseLOr())){LineInfo=token.Position};
}
if(token.Text == "&=")
{
var symbolNode = expr as SymbolNode;
if(symbolNode == null) throw new CompilerError("Assigning variable to something that is not a symbol",expr);
expr = new SetVariableNode(symbolNode.Name,new BAndNode(new GetVariableNode(symbolNode.Name),ParseLOr())){LineInfo=token.Position};
}
if(token.Text == "^=")
{
var symbolNode = expr as SymbolNode;
if(symbolNode == null) throw new CompilerError("Assigning variable to something that is not a symbol",expr);
expr = new SetVariableNode(symbolNode.Name,new XOrNode(new GetVariableNode(symbolNode.Name),ParseLOr())){LineInfo=token.Position};
}
if(token.Text == "^^=")
{
var symbolNode = expr as SymbolNode;
if(symbolNode == null) throw new CompilerError("Assigning variable to something that is not a symbol",expr);
expr = new SetVariableNode(symbolNode.Name,new PowNode(new GetVariableNode(symbolNode.Name),ParseLOr())){LineInfo=token.Position};
}
}
return expr;
}
private Node ParseLOr()
{
Node expr = ParseLAnd();
while(Context.NextEntryIsAnyOf(true,out var token,"||"))
{
expr = new LOrNode(expr,ParseLAnd()){LineInfo=token.Position};
}
return expr;
}
private Node ParseLAnd()
{
Node expr = ParseBOr();
while(Context.NextEntryIsAnyOf(true,out var token,"&&"))
{
expr = new LAndNode(expr,ParseBOr()){LineInfo=token.Position};
}
return expr;
}
private Node ParseBOr()
{
Node expr = ParseXOr();
while(Context.NextEntryIsAnyOf(true,out var token,"|"))
{
expr = new BOrNode(expr,ParseXOr()){LineInfo=token.Position};
}
return expr;
}
private Node ParseXOr()
{
Node expr = ParseBAnd();
while(Context.NextEntryIsAnyOf(true,out var token,"^"))
{
expr = new XOrNode(expr,ParseBAnd()){LineInfo=token.Position};
}
return expr;
}
private Node ParseBAnd()
{
Node expr = ParseEq();
while(Context.NextEntryIsAnyOf(true,out var token,"&"))
{
expr = new BAndNode(expr,ParseEq()){LineInfo=token.Position};
}
return expr;
}
private Node ParseEq()
{
Node expr = ParseRo();
while(Context.NextEntryIsAnyOf(true,out var token,"==","!="))
{
if(token.Text == "==")
{
expr = new EqualsNode(expr,ParseRo()){LineInfo=token.Position};
}
if(token.Text == "!=")
{
expr = new NotEqualsNode(expr,ParseRo()){LineInfo=token.Position};
}
}
return expr;
}
private Node ParseRo()
{
Node expr = ParseRo();
while(Context.NextEntryIsAnyOf(true,out var token,"<","<=",">",">="))
{
if(token.Text == "<")
{
expr = new LessThanNode(expr,ParseShift()){LineInfo=token.Position};
}
if(token.Text == "<=")
{
expr = new LessThanEqualsNode(expr,ParseShift()){LineInfo=token.Position};
}
if(token.Text == ">")
{
expr = new GreaterThanNode(expr,ParseShift()){LineInfo=token.Position};
}
if(token.Text == ">=")
{
expr = new GreaterThanEqualsNode(expr,ParseShift()){LineInfo=token.Position};
}
}
return expr;
}
private Node ParseShift()
{
Node expr = ParseSum();
while(Context.NextEntryIsAnyOf(true,out var token,"<<",">>"))
{
if(token.Text == "<<")
{
expr = new LeftShiftNode(expr,ParseSum()){LineInfo=token.Position};
}
if(token.Text == ">>")
{
expr = new RightShiftNode(expr,ParseSum()){LineInfo=token.Position};
}
}
return expr;
}
private Node ParseSum()
{
Node expr = ParseFactor();
while(Context.NextEntryIsAnyOf(true,out var token,"+","-"))
{
if(token.Text == "+")
{
expr = new AddNode(expr,ParseFactor()){LineInfo=token.Position};
}
if(token.Text == "-")
{
expr = new SubtractNode(expr,ParseFactor()){LineInfo=token.Position};
}
}
return expr;
}
private Node ParseFactor()
{
Node expr = ParseExpo();
while(Context.NextEntryIsAnyOf(true,out var token,"*","/","%"))
{
if(token.Text == "*")
{
expr = new MultiplyNode(expr,ParseExpo()){LineInfo=token.Position};
}
if(token.Text == "/")
{
expr = new DivideNode(expr,ParseExpo()){LineInfo=token.Position};
}
if(token.Text == "%")
{
expr = new ModuloNode(expr,ParseExpo()){LineInfo=token.Position};
}
}
return expr;
}
private Node ParseExpo()
{
Node expr = ParseValue();
while(Context.NextEntryIsAnyOf(true,out var token,"^^"))
{
expr = new PowNode(expr,ParseValue());
}
return expr;
}
private Node ParseValue()
{
var doc = Context.PopDocumentation();
var token = Context.NextEntry;
if(token.IsString) return new StringNode(token.Text){LineInfo = token.Position};
if(token.IsChar) return new CharNode(token.Text){LineInfo = token.Position};
if(token.Text == "(")
{
var assignable = ParseAssigable();
assignable.LineInfo = token.Position;
if(!Context.NextEntries(true,")").Success) throw new CompilerError("symbol must be a ')'",assignable);
return assignable;
}
if(token.Text == "class")
{
ClassNode classInstance = new ClassNode();
classInstance.Name = Context.NextEntry.Text;
classInstance.Documentation = doc;
if(Context.NextEntries(true,":").Success)
{
classInstance.InheritsFrom = Context.NextEntry.Text;
}
Context.NextEntries(true,"{");
while(Context.MoreTokens && !Context.NextEntries(true,"}").Success)
{
var doc2 = Context.PopDocumentation();
var token2 = Context.NextEntry;
var modifier = token2.Text;
if(Context.NextEntryIsAnyOf(true,out var token3,"func","abst"))
{
var name = Context.NextEntry.Text;
if(Context.NextEntries(true,"(").Success)
{
var pos = Context.PeekEntry.Position;
List<string> args=new List<string>();
while(!Context.NextEntries(true,")").Success)
{
if(Context.NextEntries(true,",").Success) continue;
if(Context.Offset < Context.Tokens.Count)
{
var n0 = ParseNode();
var n= n0 as GetVariableNode;
if(n != null)
{
args.Add(n.Name);
}
else
{
throw new CompilerError("Argument must be a GetVariableNode",n0);
}
}
}
ClassEntryNode nod=new ClassEntryNode(){LineInfo = token2.Position};
nod.Abstract = token3.Text == "abst";
nod.Documentation = doc2;
nod.Modifier = modifier;
nod.Name = name;
nod.InitialValue = new ClosureNode(args,ParseNode()){LineInfo = pos};
classInstance.Entries.Add(nod);
}
}
else
{
ClassEntryNode nod = new ClassEntryNode(){LineInfo = token2.Position};
nod.Documentation = doc2;
nod.Name = Context.NextEntry.Text;
if(!Context.NextEntries(true,"=").Success) throw new CompilerError("Invalid member",classInstance);
nod.Modifier = modifier;
nod.InitialValue = ParseNode();
classInstance.Entries.Add(nod);
}
}
return classInstance;
}
if(token.Text == "brk" || token.Text == "break")
{
return new BreakNode(){LineInfo = token.Position};
}
if(token.Text == "cont" || token.Text == "continue")
{
return new ContinueNode(){LineInfo = token.Position};
}
if(token.Text == "ret" || token.Text == "return")
{
return new ReturnNode(ParseNode()){LineInfo = token.Position};
}
if(token.Text == "case")
{
var expr = ParseNode();
if(!Context.NextEntries(true,":").Success) throw new CompilerError("Missing :",expr);
return new CaseNode(expr,ParseNode(true,true)){LineInfo = token.Position};
}
if(token.Text == "default")
{
var cur = Context.CurrentLineInfo;
var r=Context.NextEntries(true,":");
if(!r.Success) throw new CompilerError("Missing :",new Node(){LineInfo = cur});
return new DefaultNode(ParseNode(true,true)){LineInfo = token.Position};
}
if(token.Text == "-")
{
return new NegativeNode(ParseNode());
}
if(token.Text == "~")
{
return new BitwiseNotNode(ParseNode());
}
if(token.Text == "!")
{
return new NotNode(ParseNode());
}
if(long.TryParse(token.Text,out var number))
{
if(Context.NextEntries(true,".").Success)
{
var entry=Context.NextEntry;
if(!entry.IsChar && !entry.IsDocumentation && !entry.IsEmpty && !entry.IsString && double.TryParse($"{number}.{entry.Text}",out var number2))
{
return new ConstNumberNode(number2);
}
}
//just a long
return new ConstNumberNode(number);
}
else
{
if(Context.NextEntries(true,"(").Success)
{
if(token.Text == "func")
{
List<string> args=new List<string>();
while(!Context.NextEntries(true,")").Success)
{
if(Context.NextEntries(true,",").Success) continue;
if(Context.Offset < Context.Tokens.Count)
{
var n0 = ParseNode();
var n= n0 as GetVariableNode;
if(n != null)
{
args.Add(n.Name);
}
else
{
throw new CompilerError("Argument must be a GetVariableNode",n0);
}
}
}
return new ClosureNode(args,ParseNode());
}
else if(token.Text == "for")
{
Node init=new Node();
Node condition = new Node();
Node inc = new Node();
Node body = new Node();
if(Context.MoreTokens && (Context.PeekEntry.Text != ")" || Context.PeekEntry.Text != ";"))
{
init = ParseNode();
}
Context.NextEntries(true,";");
if(Context.MoreTokens && (Context.PeekEntry.Text != ")" || Context.PeekEntry.Text != ";"))
{
condition = ParseNode();
}
Context.NextEntries(true,";");
if(Context.MoreTokens && (Context.PeekEntry.Text != ")" || Context.PeekEntry.Text != ";"))
{
inc = ParseNode();
}
Context.NextEntries(true,")");
if(Context.MoreTokens)
body = ParseNode();
return new ForLoopNode(init,condition,inc,body);
}
else if(token.Text == "each")
{
SymbolNode varNode = new GetVariableNode("item"){LineInfo = token.Position};
Node expr = ParseNode();
if(Context.NextEntries(true,":").Success)
{
var vNode = expr as SymbolNode;
if(vNode != null)
{
varNode = vNode;
}
expr = ParseNode();
}
Context.NextEntries(true,")");
if(Context.MoreTokens)
{
return new EachLoopNode(varNode,expr,ParseNode()){LineInfo = token.Position};
}
}
else if(token.Text == "switch")
{
Node cond = ParseNode();
Context.NextEntries(true,")");
Node body = new Node();
if(!Context.NextEntries(true,";").Success)
{
body = ParseNode();
}
var scopeBody = body as ScopeNode;
if(scopeBody != null)
{
scopeBody.IsSwitchScope=true;
scopeBody.SwitchCondition = cond;
}
return body;
}
else if(token.Text == "while" || token.Text == "do")
{
Node cond = ParseNode();
Context.NextEntries(true,")");
Node body = new Node();
if(!Context.NextEntries(true,";").Success)
{
body = ParseNode();
}
return new WhileLoop(cond,body,token.Text == "do");
}
else if(token.Text == "if")
{
Node cond = ParseNode();
Context.NextEntries(true,")");
Node yes = new Node();
Node no = new Node();
if(Context.MoreTokens && !Context.NextEntries(false,"else").Success)
{
yes = ParseNode();
}
if(Context.MoreTokens && Context.NextEntries(true,"else").Success)
{
no = ParseNode();
}
return new IfNode(cond,yes,no);
}
else
{
var fcall = new FunctionCallNode(token.Text){LineInfo = token.Position};
SymbolNode ret = fcall;
while(Context.MoreTokens && !Context.NextEntries(true,")").Success)
{
if(Context.NextEntries(true,",").Success) continue;
fcall.Arguments.Add(ParseNode());
}
while(Context.MoreTokens && Context.NextEntries(true,"[").Success)
{
var p = ParseNode();
ret = new GetArrayNode(ret,p){LineInfo = p.LineInfo};
Context.NextEntries(true,"]");
}
while(Context.MoreTokens && Context.NextEntries(true,".").Success)
{
var token2 = Context.NextEntry;
if(Context.MoreTokens && Context.NextEntries(true,"(").Success)
{
var mCall = new MethodCallNode(ret,token2.Text){LineInfo=token2.Position};
ret = mCall;
while(Context.MoreTokens && !Context.NextEntries(true,")").Success)
{
if(Context.NextEntries(true,",").Success) continue;
mCall.Arguments.Add(ParseNode());
}
}
else if(Context.MoreTokens && Context.NextEntries(false,"[").Success)
{
while(Context.MoreTokens && Context.NextEntries(true,"[").Success)
{
var p = ParseNode();
ret = new GetArrayNode(ret,p){LineInfo = p.LineInfo};
Context.NextEntries(true,"]");
}
}
else
{
ret = new GetMemberNode(ret,token2.Text){LineInfo = token2.Position};
}
}
if(Context.MoreTokens && Context.NextEntries(true,"++").Success)
{
var r = new PostFixIncrementNode(ret){LineInfo = ret.LineInfo};
ret = r;
}
if(Context.MoreTokens && Context.NextEntries(true,"--").Success)
{
var r = new PostFixDecrementNode(ret){LineInfo = ret.LineInfo};
ret = r;
}
return ret;
}
}
else{
Node ret = new Node();
if(token.Text == "func")
{
var res = new GetVariableNode(Context.NextEntry.Text);
}
}
}
throw new CompilerError("End of ParseValue func",new Node(){LineInfo = token.Position});
}
}
}