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

786 lines
32 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
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)
{
if(Context.NextEntries(true,"{").Success || isRoot)
{
ScopeNode node = new ScopeNode();
node.LineInfo = Context.CurrentLineInfo;
node.RootScope = isRoot;
while(Context.Offset < Context.Tokens.Count && !Context.Tokens[Context.Offset].IsTokenWith("}"))
{
node.Add(ParseNode());
if(Context.Offset < Context.Tokens.Count && Context.Tokens[Context.Offset].IsTokenWith(";")) Context.Offset++;
}
if(!isRoot)
Context.Offset++;
return node;
}
var res= ParseAssigable();
if(Context.MoreTokens && Context.NextEntries(true,";").Success) _=0;
return res;
}
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,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,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,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,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,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,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,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,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,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,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 = ParseShift();
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 == "ensure")
{
string t = Context.NextEntry().Text;
IfNode node = new IfNode(new NotNode(new GetVariableNode(t)),new SetVariableNode(new GetVariableNode(t),new FunctionCallNode("dictionary")),new Node());
return node;
}
if(token.Text == "(")
{
var assignable = ParseAssigable();
assignable.LineInfo = token.Position;
if(!Context.NextEntries(true,")").Success) throw new CompilerError("symbol must be a ')'",assignable);
while(Context.MoreTokens && Context.NextEntries(true,"[").Success)
{
var p = ParseNode();
assignable = new GetArrayNode(assignable,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(assignable,token2.Text){LineInfo=token2.Position};
assignable = 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)
{
assignable = new GetMemberNode(assignable,token2.Text);
while(Context.MoreTokens && Context.NextEntries(true,"[").Success)
{
var p = ParseNode();
assignable = new GetArrayNode(assignable,p){LineInfo = p.LineInfo};
Context.NextEntries(true,"]");
}
}
else
{
assignable = new GetMemberNode(assignable,token2.Text){LineInfo = token2.Position};
}
}
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)
{
args.Add(Context.NextEntry().Text);
}
}
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){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(){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)
{
args.Add(Context.NextEntry().Text);
}
}
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)
{
ret = new GetMemberNode(ret,token2.Text);
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{
SymbolNode ret = new NullNode();
if(token.Text == "func")
{
var funcName= Context.NextEntry().Text;
if(Context.MoreTokens && Context.NextEntries(true,"(").Success)
{
List<string> args=new List<string>();
while(Context.MoreTokens && !Context.NextEntries(true,")").Success)
{
if(Context.NextEntries(true,",").Success) continue;
if(Context.Offset < Context.Tokens.Count)
{
args.Add(Context.NextEntry().Text);
}
}
return new FunctionDeclaritionNode( funcName,new ClosureNode(args,ParseNode())){LineInfo=token.Position};
}
}
if(token.Text == "null")
{
ret=new NullNode(){LineInfo=token.Position};
}
else if(token.Text == "undefined")
{
ret = new UndefinedNode(){LineInfo=token.Position};
}
else if(token.Text == "true")
{
ret = new TrueNode(){LineInfo=token.Position};
}
else if(token.Text == "false")
{
ret = new FalseNode(){LineInfo=token.Position};
}
else
{
ret = new GetVariableNode(token.Text){LineInfo = token.Position};
}
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)
{
ret =new GetMemberNode(ret,token2.Text);
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;
}
}
throw new CompilerError("End of ParseValue func",new Node(){LineInfo = token.Position});
}
}
}