Working on MemberGetVariableValue
This commit is contained in:
commit
b74fd1d083
|
@ -0,0 +1,133 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
x64/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.log
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.Publish.xml
|
||||
*.pubxml
|
||||
*.azurePubxml
|
||||
|
||||
# NuGet Packages Directory
|
||||
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||
packages/
|
||||
## TODO: If the tool you use requires repositories.config, also uncomment the next line
|
||||
!packages/repositories.config
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
![Ss]tyle[Cc]op.targets
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.[Pp]ublish.xml
|
||||
|
||||
*.publishsettings
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
App_Data/*.mdf
|
||||
App_Data/*.ldf
|
||||
|
||||
# =========================
|
||||
# Windows detritus
|
||||
# =========================
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Mac desktop service store files
|
||||
.DS_Store
|
||||
|
||||
_NCrunch*
|
|
@ -0,0 +1,37 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class AddNode : Node
|
||||
{
|
||||
public Node Left {get;set;}
|
||||
public Node Right {get;set;}
|
||||
|
||||
public AddNode(Node left, Node right)
|
||||
{
|
||||
this.Left = left;
|
||||
this.Right = right;
|
||||
}
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
var l=Left.Execute(nodeEnv);
|
||||
var r = Right.Execute(nodeEnv);
|
||||
var lNum = l as TNumber;
|
||||
var rNum = r as TNumber;
|
||||
var lStr = l as TString;
|
||||
var rStr = r as TString;
|
||||
|
||||
|
||||
if(lNum != null && rNum != null)
|
||||
return new TNumber(lNum.Value + rNum.Value);
|
||||
|
||||
if(lStr != null && rStr != null)
|
||||
return new TString(lStr.Value + rStr.Value);
|
||||
if(lStr != null && rNum != null)
|
||||
return new TString(lStr.Value + rNum.Value.ToString());
|
||||
if(lNum != null && rStr != null)
|
||||
return new TString(lNum.Value.ToString() + rStr.Value);
|
||||
|
||||
return new TNull();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
namespace tlang
|
||||
{
|
||||
public class ClosureNode : Node
|
||||
{
|
||||
//j=func(a,b,c,d) 4
|
||||
public ClosureNode(List<string> args,Node node)
|
||||
{
|
||||
Arguments = args;
|
||||
Node=node;
|
||||
}
|
||||
public Node Node {get;set;}
|
||||
public List<string> Arguments {get;set;}
|
||||
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
return new TInternalMethod(this,nodeEnv);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class ConstNode : Node
|
||||
{
|
||||
public TObject Value {get;set;}
|
||||
|
||||
public ConstNode(TObject value)
|
||||
{
|
||||
this.Value= value;
|
||||
}
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class DivideNode : Node
|
||||
{
|
||||
public Node Left {get;set;}
|
||||
public Node Right {get;set;}
|
||||
|
||||
public DivideNode(Node left, Node right)
|
||||
{
|
||||
this.Left = left;
|
||||
this.Right = right;
|
||||
}
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
var l = Left.Execute(nodeEnv) as TNumber;
|
||||
var r = Right.Execute(nodeEnv) as TNumber;
|
||||
|
||||
if(l != null && r != null)
|
||||
return new TNumber(l.Value / r.Value);
|
||||
|
||||
return new TNull();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class EnvironmentNode : Node
|
||||
{
|
||||
public List<Node> Nodes {get;set;}=new List<Node>();
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
|
||||
TObject returnType = TObject.Null;
|
||||
foreach(var node in Nodes)
|
||||
{
|
||||
if(node is EnvironmentNode)
|
||||
{
|
||||
returnType =node.Execute(nodeEnv.SubEnv);
|
||||
}else{
|
||||
returnType = node.Execute(nodeEnv);
|
||||
}
|
||||
}
|
||||
return returnType;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class FunctionCallNode : Node
|
||||
{
|
||||
public string Text {get;set;}
|
||||
public List<Node> Args {get;set;}
|
||||
|
||||
public FunctionCallNode(string text, List<Node> args)
|
||||
{
|
||||
this.Text = text;
|
||||
this.Args = args;
|
||||
}
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
var n = nodeEnv[Text] as ICallable;
|
||||
if(n != null)
|
||||
{
|
||||
|
||||
return n.Call(Args.Select<Node,TObject>(e=>e.Execute(nodeEnv)).ToArray());
|
||||
}
|
||||
return new TUninit();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class SetVariableNode : Node
|
||||
{
|
||||
public Node Value {get;set;}
|
||||
public string Name {get;set;}
|
||||
public SetVariableNode(string text,Node v)
|
||||
{
|
||||
Name=text;
|
||||
Value=v;
|
||||
}
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
var res=Value.Execute(nodeEnv);
|
||||
nodeEnv[Name]=res;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
public class GetVariableValue : Node
|
||||
{
|
||||
public string Name {get;set;}
|
||||
|
||||
public GetVariableValue(string text)
|
||||
{
|
||||
this.Name = text;
|
||||
}
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
return nodeEnv[Name];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class IfNode : Node
|
||||
{
|
||||
public Node Condition {get;set;}
|
||||
public Node Yes {get;set;}
|
||||
public Node No {get;set;}
|
||||
|
||||
public IfNode(Node condition, Node yes, Node no)
|
||||
{
|
||||
this.Condition = condition;
|
||||
this.Yes = yes;
|
||||
this.No = no;
|
||||
}
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
var condition = Condition.Execute(nodeEnv);
|
||||
var cInt = condition as TNumber;
|
||||
|
||||
|
||||
bool condition_bool=false;
|
||||
|
||||
if(cInt != null)
|
||||
{
|
||||
condition_bool=cInt.Value != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return condition_bool ? Yes.Execute(nodeEnv) : No.Execute(nodeEnv);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class LexToken
|
||||
{
|
||||
private LexToken(string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
|
||||
public static LexToken FromGeneralToken(int c)
|
||||
{
|
||||
return new LexToken(((char)c).ToString());
|
||||
}
|
||||
public static LexToken FromGeneralToken(string text)
|
||||
{
|
||||
return new LexToken(text);
|
||||
}
|
||||
public static LexToken FromString(string text)
|
||||
{
|
||||
return new LexToken(text){IsString = true};
|
||||
}
|
||||
public static LexToken FromChar(string text)
|
||||
{
|
||||
return new LexToken(text){IsChar = true};
|
||||
}
|
||||
public bool IsString {get;private set;}=false;
|
||||
|
||||
public bool IsChar {get;private set;}=false;
|
||||
public string Text {get;private set;}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
using System.Text;
|
||||
|
||||
namespace tlang
|
||||
{
|
||||
internal class Lexer
|
||||
{
|
||||
TextReader reader;
|
||||
public Lexer(string fName) : this(new StreamReader(fName))
|
||||
{
|
||||
|
||||
}
|
||||
public Lexer(TextReader reader)
|
||||
{
|
||||
this.reader = reader;
|
||||
}
|
||||
List<LexToken>? tokens=null;
|
||||
public List<LexToken> Tokens
|
||||
{
|
||||
get{
|
||||
if(tokens == null)
|
||||
{
|
||||
tokens = _getTokens();
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
List<LexToken> _tokens = new List<LexToken>();
|
||||
StringBuilder b = new StringBuilder();
|
||||
private void FlushBuilder()
|
||||
{
|
||||
if(b.Length > 0)
|
||||
{
|
||||
_tokens.Add(LexToken.FromGeneralToken(b.ToString()));
|
||||
b.Clear();
|
||||
}
|
||||
}
|
||||
bool escaped=false;
|
||||
private char getChar()
|
||||
{
|
||||
int read = reader.Read();
|
||||
if(read == '\\')
|
||||
{
|
||||
escaped = true;
|
||||
read = reader.Read();
|
||||
if(read == 'x')
|
||||
{
|
||||
return (char)Convert.FromHexString($"{(char)reader.Read()}{(char)reader.Read()}")[0];
|
||||
}
|
||||
else if(read == 'n')
|
||||
{
|
||||
return '\n';
|
||||
}
|
||||
else if(read == 't')
|
||||
{
|
||||
return '\t';
|
||||
}
|
||||
else if(read == 'r')
|
||||
{
|
||||
return '\r';
|
||||
}
|
||||
return (char)read;
|
||||
}
|
||||
escaped=false;
|
||||
return (char)read;
|
||||
}
|
||||
private List<LexToken> _getTokens()
|
||||
{
|
||||
|
||||
int read;
|
||||
while((read = reader.Read()) != -1)
|
||||
{
|
||||
int next=reader.Peek();
|
||||
switch(read)
|
||||
{
|
||||
case '\"':
|
||||
FlushBuilder();
|
||||
//"Some \"Some String\" Is OK"
|
||||
while(true)
|
||||
{
|
||||
char r = getChar();
|
||||
if(r == -1 || (!escaped && r == '\"'))
|
||||
{
|
||||
break;
|
||||
}
|
||||
b.Append(r);
|
||||
}
|
||||
_tokens.Add(LexToken.FromString(b.ToString()));
|
||||
b.Clear();
|
||||
break;
|
||||
case '\'':
|
||||
FlushBuilder();
|
||||
LexToken.FromChar(getChar().ToString());
|
||||
reader.Read();
|
||||
break;
|
||||
case '#':
|
||||
while(true)
|
||||
{
|
||||
read = reader.Read();
|
||||
if(read == -1) return _tokens;
|
||||
|
||||
if(read == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
FlushBuilder();
|
||||
if(next == '=')
|
||||
{
|
||||
reader.Read();
|
||||
_tokens.Add(LexToken.FromGeneralToken($"{(char)read}{(char)next}"));
|
||||
}
|
||||
else if(next == '/')
|
||||
{
|
||||
reader.Read();
|
||||
|
||||
while(true)
|
||||
{
|
||||
read = reader.Read();
|
||||
if(read == -1) return _tokens;
|
||||
|
||||
if(read == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if(next == '*')
|
||||
{
|
||||
reader.Read();
|
||||
bool lastIsAstrick=false;
|
||||
while(true)
|
||||
{
|
||||
read = reader.Read();
|
||||
if(read == -1) return _tokens;
|
||||
if(read == '*')
|
||||
{
|
||||
lastIsAstrick=true;
|
||||
continue;
|
||||
}
|
||||
else if(read == '/')
|
||||
{
|
||||
if(lastIsAstrick)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastIsAstrick=false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_tokens.Add(LexToken.FromGeneralToken(read));
|
||||
}
|
||||
|
||||
break;
|
||||
case '^':
|
||||
case '*':
|
||||
case '%':
|
||||
FlushBuilder();
|
||||
if(next == '=')
|
||||
{
|
||||
reader.Read();
|
||||
_tokens.Add(LexToken.FromGeneralToken($"{(char)read}{(char)next}"));
|
||||
}
|
||||
else
|
||||
{
|
||||
_tokens.Add(LexToken.FromGeneralToken(read));
|
||||
}
|
||||
break;
|
||||
case '|':
|
||||
case '&':
|
||||
case '<':
|
||||
case '>':
|
||||
case '+':
|
||||
case '-':
|
||||
case '!':
|
||||
FlushBuilder();
|
||||
if(next == read || next == '=')
|
||||
{
|
||||
reader.Read();
|
||||
_tokens.Add(LexToken.FromGeneralToken($"{(char)read}{(char)next}"));
|
||||
}
|
||||
else
|
||||
{
|
||||
_tokens.Add(LexToken.FromGeneralToken(read));
|
||||
}
|
||||
break;
|
||||
case '{':
|
||||
case '}':
|
||||
case '[':
|
||||
case ']':
|
||||
case '(':
|
||||
case ')':
|
||||
case '.':
|
||||
case '?':
|
||||
case ':':
|
||||
case ',':
|
||||
case ';':
|
||||
FlushBuilder();
|
||||
_tokens.Add(LexToken.FromGeneralToken(read));
|
||||
break;
|
||||
case '=':
|
||||
FlushBuilder();
|
||||
if(next == read || next == '>')
|
||||
{
|
||||
reader.Read();
|
||||
_tokens.Add(LexToken.FromGeneralToken($"{(char)read}{(char)next}"));
|
||||
}
|
||||
else
|
||||
{
|
||||
_tokens.Add(LexToken.FromGeneralToken(read));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case ' ':
|
||||
case '\n':
|
||||
case '\t':
|
||||
case '\r':
|
||||
FlushBuilder();
|
||||
break;
|
||||
default:
|
||||
b.Append((char)read);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
FlushBuilder();
|
||||
return _tokens;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class MemberFunctionCallNode : FunctionCallNode
|
||||
{
|
||||
public Node Parent {get;set;}
|
||||
|
||||
|
||||
|
||||
public MemberFunctionCallNode(Node parent, string name, List<Node> args) : base(name,args)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
}
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
var res=Parent.Execute(nodeEnv);
|
||||
|
||||
var dict = res as TDictionary;
|
||||
var integer = res as TNumber;
|
||||
|
||||
if(dict != null)
|
||||
{
|
||||
var n = dict[Text] as ICallable;
|
||||
if(n != null)
|
||||
{
|
||||
return n.Call(Args.Select<Node,TObject>(e=>e.Execute(nodeEnv)).ToArray());
|
||||
}
|
||||
}
|
||||
else if(integer != null)
|
||||
{
|
||||
if(Text == "toString")
|
||||
{
|
||||
return new TString(integer.Value.ToString());
|
||||
}
|
||||
if(Text == "abs")
|
||||
{
|
||||
return new TNumber(Math.Abs(integer.Value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(Text == "toString") return new TString("");
|
||||
|
||||
return new TUninit();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
namespace tlang
|
||||
{
|
||||
public class MemberGetVariableValue : GetVariableValue
|
||||
{
|
||||
public Node Parent {get;set;}
|
||||
public MemberGetVariableValue(Node parent,string text) : base(text)
|
||||
{
|
||||
Parent = parent;
|
||||
}
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
var res=Parent.Execute(nodeEnv);
|
||||
|
||||
var dict = res as TDictionary;
|
||||
var integer = res as TNumber;
|
||||
var array = res as TArray;
|
||||
if(array != null)
|
||||
{
|
||||
if(Name == "length" || Name == "count")
|
||||
{
|
||||
return new TNumber(array.Items.Count);
|
||||
}
|
||||
|
||||
}
|
||||
if(dict != null)
|
||||
{
|
||||
if(dict.MemberExists($"get{Name}"))
|
||||
{
|
||||
var mbm= dict[$"get{Name}"] as ICallable;
|
||||
if(mbm != null)
|
||||
return mbm.Call();
|
||||
}
|
||||
|
||||
if(dict.MemberExists(Name))
|
||||
{
|
||||
return dict[Name];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(integer != null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return new TUninit();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class ModuloNode : Node
|
||||
{
|
||||
public Node Left {get;set;}
|
||||
public Node Right {get;set;}
|
||||
|
||||
public ModuloNode(Node left, Node right)
|
||||
{
|
||||
this.Left = left;
|
||||
this.Right = right;
|
||||
}
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
var l = Left.Execute(nodeEnv) as TNumber;
|
||||
var r = Right.Execute(nodeEnv) as TNumber;
|
||||
|
||||
if(l != null && r != null)
|
||||
return new TNumber(l.Value % r.Value);
|
||||
|
||||
return new TNull();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class MultiplyNode : Node
|
||||
{
|
||||
public Node Left {get;set;}
|
||||
public Node Right {get;set;}
|
||||
|
||||
public MultiplyNode(Node left, Node right)
|
||||
{
|
||||
this.Left = left;
|
||||
this.Right = right;
|
||||
}
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
var l = Left.Execute(nodeEnv) as TNumber;
|
||||
var r = Right.Execute(nodeEnv) as TNumber;
|
||||
|
||||
if(l != null && r != null)
|
||||
return new TNumber(l.Value * r.Value);
|
||||
|
||||
return new TNull();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace tlang
|
||||
{
|
||||
public abstract class Node
|
||||
{
|
||||
public abstract TObject Execute(IScopeEnvironment nodeEnv);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class Parser
|
||||
{
|
||||
|
||||
public Parser()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Node ParseExpression(List<LexToken> tokens,ref int i,bool isFirst=false)
|
||||
{
|
||||
if(tokens[i].Text == "{" || isFirst)
|
||||
{
|
||||
if(!isFirst)
|
||||
i++;
|
||||
ScopeNode scopeNode = new ScopeNode();
|
||||
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.Name,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 TNumber(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 == "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++;
|
||||
var ret = new FunctionCallNode(token.Text,args);
|
||||
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 == "[")
|
||||
{
|
||||
|
||||
}
|
||||
else{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}else{
|
||||
switch(token.Text)
|
||||
{
|
||||
case "null":
|
||||
return new ConstNode(TObject.Null);
|
||||
case "undefined":
|
||||
return new ConstNode(TObject.Uninit);
|
||||
case "true":
|
||||
return new ConstNode(new TNumber(1));
|
||||
case "false":
|
||||
return new ConstNode(new TNumber(0));
|
||||
default:
|
||||
return new GetVariableValue(token.Text);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
namespace tlang;
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
|
||||
//Lexer lexer = new Lexer("testString.tlang");
|
||||
Parser parser = new Parser();
|
||||
//parser.Add(lexer.Tokens);
|
||||
int r=0;
|
||||
RootEnvironment env=new RootEnvironment();
|
||||
env["mol"] = new TNumber(42);
|
||||
env["printargs"] = new TExternalMethod((args2)=>{
|
||||
foreach(var arg in args2)
|
||||
{
|
||||
Console.WriteLine(arg);
|
||||
}
|
||||
return new TNumber(args2.Length);
|
||||
});
|
||||
env["int"] = new TExternalMethod((args2)=>{
|
||||
|
||||
if(args2.Length == 1)
|
||||
{
|
||||
var arg = args2[0];
|
||||
var sArg = arg as TString;
|
||||
var dArg = arg as TNumber;
|
||||
if(sArg != null)
|
||||
{
|
||||
long val;
|
||||
if(long.TryParse(sArg.Value,out val))
|
||||
{
|
||||
return new TNumber(val);
|
||||
}
|
||||
}
|
||||
if(dArg != null)
|
||||
{
|
||||
return new TNumber(Math.Round(dArg.Value));
|
||||
}
|
||||
|
||||
}
|
||||
return TObject.Null;
|
||||
});
|
||||
|
||||
env["filecreate"]=new TExternalMethod((args2)=>{
|
||||
|
||||
if(args2.Length == 1)
|
||||
{
|
||||
var fileName = args2[0] as TString;
|
||||
if(fileName != null)
|
||||
{
|
||||
return new TInternalObject(File.Create(fileName.Value));
|
||||
}
|
||||
}
|
||||
return new TNull();
|
||||
});
|
||||
env["streamwritestr"]=new TExternalMethod((args2)=>{
|
||||
if(args2.Length == 2)
|
||||
{
|
||||
var internalObj = args2[0] as TInternalObject;
|
||||
if(internalObj != null)
|
||||
{
|
||||
var strm = internalObj.Object as Stream;
|
||||
if(strm != null)
|
||||
{
|
||||
var str = args2[1] as TString;
|
||||
if(str != null)
|
||||
{
|
||||
var bytes=System.Text.Encoding.UTF8.GetBytes(str.Value);
|
||||
strm.Write(bytes,0,bytes.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return TObject.Null;
|
||||
});
|
||||
env["streamclose"]=new TExternalMethod((args2)=>{
|
||||
if(args2.Length == 1)
|
||||
{
|
||||
var internalObj = args2[0] as TInternalObject;
|
||||
if(internalObj != null)
|
||||
{
|
||||
var strm = internalObj.Object as Stream;
|
||||
if(strm != null)
|
||||
{
|
||||
strm.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
return TObject.Null;
|
||||
});
|
||||
|
||||
Lexer lexer =new Lexer(new StreamReader("file.tlang"));
|
||||
var res=parser.ParseExpression(lexer.Tokens,ref r,true).Execute(env);
|
||||
r=0;
|
||||
Console.WriteLine(res);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace tlang
|
||||
{
|
||||
public interface IScopeEnvironment : IEnumerable<KeyValuePair<string,TObject>>
|
||||
{
|
||||
bool VariableExists(string name);
|
||||
void SetVariable(string name,TObject obj);
|
||||
TObject GetVariable(string names);
|
||||
|
||||
IScopeEnvironment SubEnv {get;}
|
||||
|
||||
IScopeEnvironment RootEnv {get;}
|
||||
|
||||
TObject this[string variable] {get;set;}
|
||||
}
|
||||
public class SubEnvironment : IScopeEnvironment
|
||||
{
|
||||
Dictionary<string,TObject> items = new Dictionary<string, TObject>();
|
||||
|
||||
IScopeEnvironment root;
|
||||
IScopeEnvironment parent;
|
||||
|
||||
public SubEnvironment(IScopeEnvironment root,IScopeEnvironment parent)
|
||||
{
|
||||
this.root=root;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public TObject this[string variable] { get => GetVariable(variable); set => SetVariable(variable,value); }
|
||||
|
||||
public IScopeEnvironment SubEnv => new SubEnvironment(root,this);
|
||||
|
||||
public IScopeEnvironment RootEnv => root;
|
||||
|
||||
public IEnumerator<KeyValuePair<string, TObject>> GetEnumerator()
|
||||
{
|
||||
return getVars().GetEnumerator();
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string,TObject>> getVars()
|
||||
{
|
||||
foreach(var v in parent)
|
||||
{
|
||||
yield return v;
|
||||
}
|
||||
foreach(var item in items)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
|
||||
public TObject GetVariable(string name)
|
||||
{
|
||||
if(parent.VariableExists(name))
|
||||
{
|
||||
return parent[name];
|
||||
}
|
||||
if(items.ContainsKey(name))
|
||||
{
|
||||
return items[name];
|
||||
}
|
||||
return TObject.Uninit;
|
||||
}
|
||||
|
||||
public void SetVariable(string name, TObject obj)
|
||||
{
|
||||
if(parent.VariableExists(name))
|
||||
{
|
||||
parent.SetVariable(name,obj);
|
||||
}else if(items.ContainsKey(name))
|
||||
{
|
||||
items[name] = obj;
|
||||
}else{
|
||||
items.Add(name,obj);
|
||||
}
|
||||
}
|
||||
|
||||
public bool VariableExists(string name)
|
||||
{
|
||||
if(parent.VariableExists(name)) return true;
|
||||
return items.ContainsKey(name);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return getVars().GetEnumerator();
|
||||
}
|
||||
}
|
||||
public class RootEnvironment : IScopeEnvironment
|
||||
{
|
||||
Dictionary<string,TObject> items = new Dictionary<string, TObject>();
|
||||
|
||||
public IScopeEnvironment SubEnv => new SubEnvironment(this,this);
|
||||
|
||||
public IScopeEnvironment RootEnv => this;
|
||||
|
||||
public IEnumerator<KeyValuePair<string, TObject>> GetEnumerator()
|
||||
{
|
||||
return items.GetEnumerator();
|
||||
}
|
||||
|
||||
public TObject GetVariable(string name)
|
||||
{
|
||||
if(items.ContainsKey(name))
|
||||
{
|
||||
return items[name];
|
||||
}else{
|
||||
return TObject.Uninit;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVariable(string name, TObject obj)
|
||||
{
|
||||
if(items.ContainsKey(name))
|
||||
{
|
||||
items[name] = obj;
|
||||
}
|
||||
else
|
||||
{
|
||||
items.Add(name,obj);
|
||||
}
|
||||
}
|
||||
|
||||
public bool VariableExists(string name)
|
||||
{
|
||||
return items.ContainsKey(name);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return items.GetEnumerator();
|
||||
}
|
||||
public TObject this[string variable] { get => GetVariable(variable); set => SetVariable(variable,value); }
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
namespace tlang
|
||||
{
|
||||
public class ScopeNode : Node
|
||||
{
|
||||
public List<Node> Body {get;set;}= new List<Node>();
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
var sub = nodeEnv.SubEnv;
|
||||
TObject obj=new TNull();
|
||||
foreach(var item in Body)
|
||||
{
|
||||
obj=item.Execute(sub);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
namespace tlang
|
||||
{
|
||||
internal class SubtractNode : Node
|
||||
{
|
||||
public Node Left {get;set;}
|
||||
public Node Right {get;set;}
|
||||
|
||||
public SubtractNode(Node left, Node right)
|
||||
{
|
||||
this.Left = left;
|
||||
this.Right = right;
|
||||
}
|
||||
|
||||
public override TObject Execute(IScopeEnvironment nodeEnv)
|
||||
{
|
||||
var l = Left.Execute(nodeEnv) as TNumber;
|
||||
var r = Right.Execute(nodeEnv) as TNumber;
|
||||
|
||||
if(l != null && r != null)
|
||||
return new TNumber(l.Value - r.Value);
|
||||
|
||||
return new TNull();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
namespace tlang
|
||||
{
|
||||
public class TArray : TObject
|
||||
{
|
||||
public TArray()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public List<TObject> Items {get;set;}=new List<TObject>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
namespace tlang
|
||||
{
|
||||
public class TDictionary : TObject
|
||||
{
|
||||
public TDictionary()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Dictionary<string,TObject> items {get;set;}=new Dictionary<string, TObject>();
|
||||
|
||||
public TObject GetMember(string name)
|
||||
{
|
||||
if(items.ContainsKey(name))
|
||||
{
|
||||
return items[name];
|
||||
}else{
|
||||
return TObject.Uninit;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetMember(string name, TObject obj)
|
||||
{
|
||||
if(items.ContainsKey(name))
|
||||
{
|
||||
items[name] = obj;
|
||||
}
|
||||
else
|
||||
{
|
||||
items.Add(name,obj);
|
||||
}
|
||||
}
|
||||
|
||||
public bool MemberExists(string name)
|
||||
{
|
||||
return items.ContainsKey(name);
|
||||
}
|
||||
public TObject this[string variable] { get => GetMember(variable); set => SetMember(variable,value); }
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace tlang
|
||||
{
|
||||
public class TInternalObject : TObject
|
||||
{
|
||||
public TInternalObject(object val)
|
||||
{
|
||||
Object=val;
|
||||
}
|
||||
public object Object {get;set;}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
namespace tlang
|
||||
{
|
||||
public class TInternalMethod : TObject, ICallable
|
||||
{
|
||||
public TInternalMethod(ClosureNode node,IScopeEnvironment env)
|
||||
{
|
||||
Body = node;
|
||||
Environment = env;
|
||||
}
|
||||
public ClosureNode Body {get;set;}
|
||||
public IScopeEnvironment Environment {get;set;}
|
||||
public TObject Call(params TObject[] args)
|
||||
{
|
||||
var env=Environment.SubEnv;
|
||||
int argCountClosure = Body.Arguments.Count;
|
||||
int argCountCaller = args.Length;
|
||||
if(argCountCaller < requiredArguments())
|
||||
{
|
||||
throw new Exception("not enough arguments");
|
||||
}
|
||||
int i = 0;
|
||||
for(;i<optionalArgs(args.Length);i++)
|
||||
{
|
||||
env[Body.Arguments[i].TrimStart('.')] = args[i];
|
||||
}
|
||||
if(i==Body.Arguments.Count-1)
|
||||
{
|
||||
var tarray = new TArray();
|
||||
env[Body.Arguments[i].TrimStart('.')] =tarray;
|
||||
for(int j = i;j<args.Length;j++)
|
||||
{
|
||||
tarray.Items.Add(args[j]);
|
||||
}
|
||||
}
|
||||
return Body.Node.Execute(env);
|
||||
}
|
||||
private int optionalArgs(int argLen)
|
||||
{
|
||||
for(int i =0;i<Body.Arguments.Count;i++)
|
||||
{
|
||||
if(Body.Arguments[i].StartsWith("..."))
|
||||
{
|
||||
return Math.Min(argLen,i);
|
||||
}
|
||||
}
|
||||
return Math.Min(argLen,Body.Arguments.Count);
|
||||
}
|
||||
private int requiredArguments()
|
||||
{
|
||||
for(int i =0;i<Body.Arguments.Count;i++)
|
||||
{
|
||||
if(Body.Arguments[i].StartsWith('.'))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return Body.Arguments.Count;
|
||||
}
|
||||
|
||||
}
|
||||
public class TExternalMethod : TObject,ICallable
|
||||
{
|
||||
Func<TObject[],TObject> cb;
|
||||
public TExternalMethod(Func<TObject[],TObject> func)
|
||||
{
|
||||
cb = func;
|
||||
}
|
||||
|
||||
public TObject Call(params TObject[] args)
|
||||
{
|
||||
return cb(args);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public interface ICallable
|
||||
{
|
||||
TObject Call(params TObject[] args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace tlang
|
||||
{
|
||||
public class TNull : TObject
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
namespace tlang
|
||||
{
|
||||
public class TNumber : TObject
|
||||
{
|
||||
public double Value {get;set;}
|
||||
public TNumber(double number)
|
||||
{
|
||||
Value = number;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
namespace tlang
|
||||
{
|
||||
public class TObject
|
||||
{
|
||||
|
||||
public static TObject Uninit => new TUninit();
|
||||
public static TObject Null => new TNull();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
namespace tlang
|
||||
{
|
||||
public class TString : TObject
|
||||
{
|
||||
public string Value {get;set;}
|
||||
public TString(string text)
|
||||
{
|
||||
Value = text;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace tlang
|
||||
{
|
||||
public class TUninit : TObject
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return "undefined";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
if(expression) expression else expression
|
||||
*/
|
||||
|
||||
j = func() 42-43;
|
||||
|
||||
printargs(j().abs());
|
|
@ -0,0 +1,7 @@
|
|||
var s1="Some \"Some String\" Is Cool";
|
||||
var s2="My String Is Awesome";
|
||||
var s3="Demi\nLovato";
|
||||
|
||||
var main = (args)=>{
|
||||
ret 0;
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
Loading…
Reference in New Issue