tlang-interperter-cs/Parser.cs

484 lines
19 KiB
C#

namespace tlang
{
internal class Parser
{
public Parser()
{
}
public Node ParseExpression(List<LexToken> tokens,ref int i,bool isFirst=false)
{
if(i>= tokens.Count) return new ConstNode(new TNumber(0));
if(tokens[i].Text == "{" || isFirst)
{
if(!isFirst)
i++;
ScopeNode scopeNode = new ScopeNode(){First=isFirst};
while(i<tokens.Count && tokens[i].Text != "}")
{
scopeNode.Body.Add(ParseExpression(tokens,ref i));
if(i<tokens.Count && tokens[i].Text == ";")
{
i++;
}
}
i++;
return scopeNode;
}else{
return ParseAssignable(tokens,ref i);
}
}
private Node ParseAssignable(List<LexToken> tokens,ref int i)
{
Node myExpression = ParseSum(tokens,ref i);
while(i<tokens.Count && (tokens[i].Text == "="))
{
if(i<tokens.Count && tokens[i].Text == "=")
{
i++;
GetVariableValue? gvar = myExpression as GetVariableValue;
if(gvar != null)
{
myExpression= new SetVariableNode(gvar,ParseSum(tokens,ref i));
}
}
}
return myExpression;
}
private Node ParseSum(List<LexToken> tokens,ref int i)
{
Node myExpression = ParseFactor(tokens,ref i);
while(i<tokens.Count && (tokens[i].Text == "+" || tokens[i].Text == "-"))
{
if(i<tokens.Count && tokens[i].Text == "+"){
i++;
myExpression = new AddNode(myExpression,ParseFactor(tokens,ref i));
}
if(i<tokens.Count && tokens[i].Text == "-")
{
i++;
myExpression = new SubtractNode(myExpression,ParseFactor(tokens,ref i));
}
}
return myExpression;
}
private Node ParseValue(List<LexToken> tokens,ref int i)
{
var token=tokens[i++];
if(token.IsString) return new ConstNode(new TString(token.Text));
if(token.IsChar)
{
return new ConstNode(new TChar(token.Text.SingleOrDefault()));
}
long val;
if(long.TryParse(token.Text,out val))
{
if(i<tokens.Count && tokens[i].Text == "." && !tokens[i].IsChar && !tokens[i].IsString)
{
i++;
if(i<tokens.Count)
{
var token2=tokens[i++];
double dblR;
if(double.TryParse($"{val}.{token2.Text}",out dblR))
{
return new ConstNode(new TNumber(dblR));
}
}
}else{
return new ConstNode(new TNumber( val ));
}
}
else {
if(i<tokens.Count && tokens[i].Text=="(")
{
if(token.Text == "func")
{
List<string> args = new List<string>();
i++;
while(i<tokens.Count && tokens[i].Text != ")")
{
if(tokens[i].Text == ",") {i++;continue;}
if(i<tokens.Count)
{
var exp = ParseExpression(tokens,ref i);
var gvExp = exp as GetVariableValue;
if(gvExp != null)
{
args.Add(gvExp.Name);
}else{
throw new Exception("not a getvariablenode");
}
}
}
i++;
return new ClosureNode(args,ParseExpression(tokens,ref i));
}
else if(token.Text == "for")
{
i++;
//init;condition;inc)
Node init = new ConstNode(new TUninit());
Node condition = new ConstNode(new TUninit());
Node inc = new ConstNode(new TUninit());
Node body = new ConstNode(new TUninit());
if(i<tokens.Count && (tokens[i].Text != ")" || tokens[i].Text != ";"))
{
init = ParseExpression(tokens,ref i);
}
if(i<tokens.Count && tokens[i].Text == ";")
i++;
if(i<tokens.Count && (tokens[i].Text != ")" || tokens[i].Text != ";"))
{
condition = ParseExpression(tokens,ref i);
}
if(i<tokens.Count && tokens[i].Text == ";")
i++;
if(i<tokens.Count && (tokens[i].Text != ")" || tokens[i].Text != ";"))
{
inc = ParseExpression(tokens,ref i);
}
if(i<tokens.Count && tokens[i].Text == ")")
i++;
if(i<tokens.Count)
body = ParseExpression(tokens,ref i);
return new ForLoop(init,condition,inc,body);
}
else if(token.Text == "each")
{
i++;
Node ls = ParseExpression(tokens,ref i);
GetVariableValue? name = new GetVariableValue("item");
if(i<tokens.Count && tokens[i].Text == ":")
{
i++;
var n=ls as GetVariableValue;
if(n != null) name = n;
ls = ParseExpression(tokens,ref i);
}
i++;
if(i<tokens.Count)
{
return new EachLoop(name,ls,ParseExpression(tokens,ref i));
}
}
else if(token.Text == "while")
{
i++;
var condition=ParseExpression(tokens,ref i);
i++;
Node yes = new ConstNode(new TUninit());
if(i<tokens.Count && tokens[i].Text != ";")
yes = ParseExpression(tokens,ref i);
return new WhileLoop(condition,yes,false);
}
else if(token.Text == "do")
{
i++;
var condition=ParseExpression(tokens,ref i);
i++;
Node yes = new ConstNode(new TUninit());
if(i<tokens.Count && tokens[i].Text != ";")
yes = ParseExpression(tokens,ref i);
return new WhileLoop(condition,yes,true);
}
else if(token.Text == "if")
{
i++;
var condition=ParseExpression(tokens,ref i);
i++;
Node yes = new ConstNode(new TUninit());
Node no = new ConstNode(new TUninit());
if(i<tokens.Count && tokens[i].Text != "else")
yes=ParseExpression(tokens,ref i);
if(i<tokens.Count && tokens[i].Text == "else")
{
i++;
no = ParseExpression(tokens,ref i);
}
return new IfNode(condition,yes,no);
}
else{
i++;
List<Node> args = new List<Node>();
//function call baby
while(i<tokens.Count && tokens[i].Text != ")")
{
if(tokens[i].Text == ",") {i++;continue;}
if(i<tokens.Count)
{
args.Add(ParseExpression(tokens,ref i));
}
}
i++;
Node ret = new FunctionCallNode(token.Text,args);
while(i<tokens.Count && tokens[i].Text == "[")
{
i++;
var arg = ParseExpression(tokens,ref i);
i++;
ret = new ArraySubscriptNode(ret,token.Text,arg);
}
while(i<tokens.Count && tokens[i].Text == ".")
{
i++;
var token2 = tokens[i++];
if(i<tokens.Count && tokens[i].Text == "(")
{
i++;
args = new List<Node>();
//function call baby
while(i<tokens.Count && tokens[i].Text != ")")
{
if(tokens[i].Text == ",") {i++;continue;}
if(i<tokens.Count)
{
args.Add(ParseExpression(tokens,ref i));
}
}
i++;
ret = new MemberFunctionCallNode(ret,token2.Text,args);
}
else if(i<tokens.Count && tokens[i].Text == "[")
{
i++;
var arg = ParseExpression(tokens,ref i);
i++;
ret = new ArraySubscriptNode(ret,token2.Text,arg);
}
else{
ret = new MemberGetVariableValue(ret,token2.Text);
}
}
if(i<tokens.Count && tokens[i].Text == "++")
{
var mgvn = ret as GetVariableValue;
i++;
if(mgvn != null)
{
return new PostfixIncrementVariableNode(mgvn);
}
}
if(i<tokens.Count && tokens[i].Text == "--")
{
var mgvn = ret as GetVariableValue;
i++;
if(mgvn != null)
{
return new PostfixDecrementVariableNode(mgvn);
}
}
return ret;
}
}else{
Node ret;
switch(token.Text)
{
case "null":
ret= new ConstNode(TObject.Null);
break;
case "undefined":
ret= new ConstNode(TObject.Uninit);
break;
case "true":
ret= new ConstNode(new TNumber(1));
break;
case "false":
ret= new ConstNode(new TNumber(0));
break;
default:
ret= new GetVariableValue(token.Text);
break;
}
while(i<tokens.Count && tokens[i].Text == "[")
{
i++;
var arg = ParseExpression(tokens,ref i);
i++;
ret = new ArraySubscriptNode(ret,token.Text,arg);
}
while(i<tokens.Count && tokens[i].Text == ".")
{
i++;
var token2 = tokens[i++];
if(i<tokens.Count && tokens[i].Text == "(")
{
i++;
var args = new List<Node>();
//function call baby
while(i<tokens.Count && tokens[i].Text != ")")
{
if(tokens[i].Text == ",") {i++;continue;}
if(i<tokens.Count)
{
args.Add(ParseExpression(tokens,ref i));
}
}
i++;
ret = new MemberFunctionCallNode(ret,token2.Text,args);
}
else if(i<tokens.Count && tokens[i].Text == "[")
{
i++;
var arg = ParseExpression(tokens,ref i);
i++;
ret = new ArraySubscriptNode(ret,token2.Text,arg);
}
else{
ret = new MemberGetVariableValue(ret,token2.Text);
}
}
if(i<tokens.Count && tokens[i].Text == "++")
{
var mgvn = ret as GetVariableValue;
i++;
if(mgvn != null)
{
return new PostfixIncrementVariableNode(mgvn);
}
}
if(i<tokens.Count && tokens[i].Text == "--")
{
var mgvn = ret as GetVariableValue;
i++;
if(mgvn != null)
{
return new PostfixDecrementVariableNode(mgvn);
}
}
return ret;
}
}
throw new Exception();
}
private Node ParseFactor(List<LexToken> tokens,ref int i)
{
Node myExpression = ParseValue(tokens,ref i);
while(i<tokens.Count && (tokens[i].Text == "*" || tokens[i].Text == "/" || tokens[i].Text == "%"))
{
if(i<tokens.Count && tokens[i].Text == "*"){
i++;
myExpression = new MultiplyNode(myExpression,ParseValue(tokens,ref i));
}
if(i<tokens.Count && tokens[i].Text == "/")
{
i++;
myExpression = new DivideNode(myExpression,ParseValue(tokens,ref i));
}
if(i<tokens.Count && tokens[i].Text == "%")
{
i++;
myExpression = new ModuloNode(myExpression,ParseValue(tokens,ref i));
}
}
return myExpression;
}
public void LoadEnvironment(RootEnvironment env)
{
TDictionary fs = new TDictionary();
fs["enumerate_files"] = new TExternalMethod((args)=>{
if(args.Length > 0)
{
var fileName=args[0].ToString();
if(!string.IsNullOrWhiteSpace(fileName) && Directory.Exists(fileName))
{
var dict = new TDictionary();
dict["getIttr"] = new TExternalMethod((args2)=>{
var enumerable=Directory.EnumerateFiles(fileName).GetEnumerator();
TDictionary dict2 = new TDictionary();
dict2["movenext"] = new TExternalMethod((args3)=>{
return new TNumber(enumerable.MoveNext() ? 1 : 0);
});
dict2["getCurrent"] = new TExternalMethod((args3)=>{
return new TString(enumerable.Current);
});
return dict2;
});
return dict;
}
}
return TObject.Null;
});
fs["enumerate_dirs"] = new TExternalMethod((args)=>{
if(args.Length > 0)
{
var fileName=args[0].ToString();
if(!string.IsNullOrWhiteSpace(fileName) && Directory.Exists(fileName))
{
var dict = new TDictionary();
dict["getIttr"] = new TExternalMethod((args2)=>{
var enumerable=Directory.EnumerateDirectories(fileName).GetEnumerator();
TDictionary dict2 = new TDictionary();
dict2["movenext"] = new TExternalMethod((args3)=>{
return new TNumber(enumerable.MoveNext() ? 1 : 0);
});
dict2["getCurrent"] = new TExternalMethod((args3)=>{
return new TString(enumerable.Current);
});
return dict2;
});
return dict;
}
}
return TObject.Null;
});
env["fs"]=fs;
}
}
}