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(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,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 = 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 args=new List(); 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 args=new List(); 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{ SymbolNode ret = new NullNode(); if(token.Text == "func") { var res = new GetVariableNode(Context.NextEntry.Text); if(Context.MoreTokens && Context.NextEntries(true,"(").Success) { List args=new List(); 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 SetVariableNode( res,new ClosureNode(args,ParseNode())); } } 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) { 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}); } } }