Working on MemberGetVariableValue

This commit is contained in:
Mike Nolan 2023-03-09 13:40:14 -06:00
commit b74fd1d083
33 changed files with 1527 additions and 0 deletions

133
.gitignore vendored Normal file
View File

@ -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*

37
AddNode.cs Normal file
View File

@ -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();
}
}
}

20
ClosureNode.cs Normal file
View File

@ -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);
}
}
}

17
ConstNode.cs Normal file
View File

@ -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;
}
}
}

25
DivideNode.cs Normal file
View File

@ -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();
}
}
}

23
EnvironmentNode.cs Normal file
View File

@ -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;
}
}
}

25
FunctionCallNode.cs Normal file
View File

@ -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();
}
}
}

34
GetVariableValue.cs Normal file
View File

@ -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];
}
}
}

34
IfNode.cs Normal file
View File

@ -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);
}
}
}

31
LexToken.cs Normal file
View File

@ -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;}
}
}

237
Lexer.cs Normal file
View File

@ -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;
}
}
}

47
MemberFunctionCallNode.cs Normal file
View File

@ -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();
}
}
}

50
MemberGetValueNode.cs Normal file
View File

@ -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();
}
}
}

25
ModuloNode.cs Normal file
View File

@ -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();
}
}
}

25
MultiplyNode.cs Normal file
View File

@ -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();
}
}
}

7
Node.cs Normal file
View File

@ -0,0 +1,7 @@
namespace tlang
{
public abstract class Node
{
public abstract TObject Execute(IScopeEnvironment nodeEnv);
}
}

247
Parser.cs Normal file
View File

@ -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;
}
}
}

98
Program.cs Normal file
View File

@ -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);
}
}

139
ScopeEnvironment.cs Normal file
View File

@ -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); }
}
}

17
ScopeNode.cs Normal file
View File

@ -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;
}
}
}

25
SubtractNode.cs Normal file
View File

@ -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();
}
}
}

12
TArray.cs Normal file
View File

@ -0,0 +1,12 @@
namespace tlang
{
public class TArray : TObject
{
public TArray()
{
}
public List<TObject> Items {get;set;}=new List<TObject>();
}
}

42
TDictionary.cs Normal file
View File

@ -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); }
}
}

11
TInternalObject.cs Normal file
View File

@ -0,0 +1,11 @@
namespace tlang
{
public class TInternalObject : TObject
{
public TInternalObject(object val)
{
Object=val;
}
public object Object {get;set;}
}
}

81
TMethod.cs Normal file
View File

@ -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);
}
}

10
TNull.cs Normal file
View File

@ -0,0 +1,10 @@
namespace tlang
{
public class TNull : TObject
{
public override string ToString()
{
return "null";
}
}
}

17
TNumber.cs Normal file
View File

@ -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();
}
}
}

9
TObject.cs Normal file
View File

@ -0,0 +1,9 @@
namespace tlang
{
public class TObject
{
public static TObject Uninit => new TUninit();
public static TObject Null => new TNull();
}
}

15
TString.cs Normal file
View File

@ -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;
}
}
}

10
TUninit.cs Normal file
View File

@ -0,0 +1,10 @@
namespace tlang
{
public class TUninit : TObject
{
public override string ToString()
{
return "undefined";
}
}
}

7
file.tlang Normal file
View File

@ -0,0 +1,7 @@
/*
if(expression) expression else expression
*/
j = func() 42-43;
printargs(j().abs());

7
testString.tlang Normal file
View File

@ -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;
};

10
tlang.csproj Normal file
View File

@ -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>