From b74fd1d08354fa92a2cb0eea6ed272beabd19400 Mon Sep 17 00:00:00 2001 From: Mike Nolan Date: Thu, 9 Mar 2023 13:40:14 -0600 Subject: [PATCH] Working on MemberGetVariableValue --- .gitignore | 133 ++++++++++++++++++++ AddNode.cs | 37 ++++++ ClosureNode.cs | 20 +++ ConstNode.cs | 17 +++ DivideNode.cs | 25 ++++ EnvironmentNode.cs | 23 ++++ FunctionCallNode.cs | 25 ++++ GetVariableValue.cs | 34 ++++++ IfNode.cs | 34 ++++++ LexToken.cs | 31 +++++ Lexer.cs | 237 ++++++++++++++++++++++++++++++++++++ MemberFunctionCallNode.cs | 47 ++++++++ MemberGetValueNode.cs | 50 ++++++++ ModuloNode.cs | 25 ++++ MultiplyNode.cs | 25 ++++ Node.cs | 7 ++ Parser.cs | 247 ++++++++++++++++++++++++++++++++++++++ Program.cs | 98 +++++++++++++++ ScopeEnvironment.cs | 139 +++++++++++++++++++++ ScopeNode.cs | 17 +++ SubtractNode.cs | 25 ++++ TArray.cs | 12 ++ TDictionary.cs | 42 +++++++ TInternalObject.cs | 11 ++ TMethod.cs | 81 +++++++++++++ TNull.cs | 10 ++ TNumber.cs | 17 +++ TObject.cs | 9 ++ TString.cs | 15 +++ TUninit.cs | 10 ++ file.tlang | 7 ++ testString.tlang | 7 ++ tlang.csproj | 10 ++ 33 files changed, 1527 insertions(+) create mode 100644 .gitignore create mode 100644 AddNode.cs create mode 100644 ClosureNode.cs create mode 100644 ConstNode.cs create mode 100644 DivideNode.cs create mode 100644 EnvironmentNode.cs create mode 100644 FunctionCallNode.cs create mode 100644 GetVariableValue.cs create mode 100644 IfNode.cs create mode 100644 LexToken.cs create mode 100644 Lexer.cs create mode 100644 MemberFunctionCallNode.cs create mode 100644 MemberGetValueNode.cs create mode 100644 ModuloNode.cs create mode 100644 MultiplyNode.cs create mode 100644 Node.cs create mode 100644 Parser.cs create mode 100644 Program.cs create mode 100644 ScopeEnvironment.cs create mode 100644 ScopeNode.cs create mode 100644 SubtractNode.cs create mode 100644 TArray.cs create mode 100644 TDictionary.cs create mode 100644 TInternalObject.cs create mode 100644 TMethod.cs create mode 100644 TNull.cs create mode 100644 TNumber.cs create mode 100644 TObject.cs create mode 100644 TString.cs create mode 100644 TUninit.cs create mode 100644 file.tlang create mode 100644 testString.tlang create mode 100644 tlang.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b956f9 --- /dev/null +++ b/.gitignore @@ -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* \ No newline at end of file diff --git a/AddNode.cs b/AddNode.cs new file mode 100644 index 0000000..18c949a --- /dev/null +++ b/AddNode.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/ClosureNode.cs b/ClosureNode.cs new file mode 100644 index 0000000..2736870 --- /dev/null +++ b/ClosureNode.cs @@ -0,0 +1,20 @@ +namespace tlang +{ + public class ClosureNode : Node + { + //j=func(a,b,c,d) 4 + public ClosureNode(List args,Node node) + { + Arguments = args; + Node=node; + } + public Node Node {get;set;} + public List Arguments {get;set;} + + + public override TObject Execute(IScopeEnvironment nodeEnv) + { + return new TInternalMethod(this,nodeEnv); + } + } +} \ No newline at end of file diff --git a/ConstNode.cs b/ConstNode.cs new file mode 100644 index 0000000..fe62d9a --- /dev/null +++ b/ConstNode.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/DivideNode.cs b/DivideNode.cs new file mode 100644 index 0000000..94728b2 --- /dev/null +++ b/DivideNode.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/EnvironmentNode.cs b/EnvironmentNode.cs new file mode 100644 index 0000000..3188325 --- /dev/null +++ b/EnvironmentNode.cs @@ -0,0 +1,23 @@ +namespace tlang +{ + internal class EnvironmentNode : Node + { + public List Nodes {get;set;}=new List(); + + 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; + } + } +} \ No newline at end of file diff --git a/FunctionCallNode.cs b/FunctionCallNode.cs new file mode 100644 index 0000000..10038ea --- /dev/null +++ b/FunctionCallNode.cs @@ -0,0 +1,25 @@ +namespace tlang +{ + internal class FunctionCallNode : Node + { + public string Text {get;set;} + public List Args {get;set;} + + public FunctionCallNode(string text, List 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(e=>e.Execute(nodeEnv)).ToArray()); + } + return new TUninit(); + } + } +} \ No newline at end of file diff --git a/GetVariableValue.cs b/GetVariableValue.cs new file mode 100644 index 0000000..e0b6356 --- /dev/null +++ b/GetVariableValue.cs @@ -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]; + } + } +} \ No newline at end of file diff --git a/IfNode.cs b/IfNode.cs new file mode 100644 index 0000000..0c4ff79 --- /dev/null +++ b/IfNode.cs @@ -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); + } + } +} \ No newline at end of file diff --git a/LexToken.cs b/LexToken.cs new file mode 100644 index 0000000..4802d82 --- /dev/null +++ b/LexToken.cs @@ -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;} + } +} \ No newline at end of file diff --git a/Lexer.cs b/Lexer.cs new file mode 100644 index 0000000..52421d9 --- /dev/null +++ b/Lexer.cs @@ -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? tokens=null; + public List Tokens + { + get{ + if(tokens == null) + { + tokens = _getTokens(); + } + return tokens; + } + } + List _tokens = new List(); + 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 _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; + } + } +} \ No newline at end of file diff --git a/MemberFunctionCallNode.cs b/MemberFunctionCallNode.cs new file mode 100644 index 0000000..182d980 --- /dev/null +++ b/MemberFunctionCallNode.cs @@ -0,0 +1,47 @@ +namespace tlang +{ + internal class MemberFunctionCallNode : FunctionCallNode + { + public Node Parent {get;set;} + + + + public MemberFunctionCallNode(Node parent, string name, List 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(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(); + } + } +} \ No newline at end of file diff --git a/MemberGetValueNode.cs b/MemberGetValueNode.cs new file mode 100644 index 0000000..2c1fc35 --- /dev/null +++ b/MemberGetValueNode.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/ModuloNode.cs b/ModuloNode.cs new file mode 100644 index 0000000..76c8d4f --- /dev/null +++ b/ModuloNode.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/MultiplyNode.cs b/MultiplyNode.cs new file mode 100644 index 0000000..6c588fc --- /dev/null +++ b/MultiplyNode.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/Node.cs b/Node.cs new file mode 100644 index 0000000..d073cd1 --- /dev/null +++ b/Node.cs @@ -0,0 +1,7 @@ +namespace tlang +{ + public abstract class Node + { + public abstract TObject Execute(IScopeEnvironment nodeEnv); + } +} \ No newline at end of file diff --git a/Parser.cs b/Parser.cs new file mode 100644 index 0000000..1eedfda --- /dev/null +++ b/Parser.cs @@ -0,0 +1,247 @@ +namespace tlang +{ + internal class Parser + { + + public Parser() + { + + } + + public Node ParseExpression(List tokens,ref int i,bool isFirst=false) + { + if(tokens[i].Text == "{" || isFirst) + { + if(!isFirst) + i++; + ScopeNode scopeNode = new ScopeNode(); + while(i tokens,ref int i) + { + Node myExpression = ParseSum(tokens,ref i); + while(i tokens,ref int i) + { + Node myExpression = ParseFactor(tokens,ref i); + while(i 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 args = new List(); + i++; + while(i args = new List(); + //function call baby + while(i(); + //function call baby + while(i tokens,ref int i) + { + Node myExpression = ParseValue(tokens,ref i); + while(i{ + 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); + + } +} diff --git a/ScopeEnvironment.cs b/ScopeEnvironment.cs new file mode 100644 index 0000000..f2bf78c --- /dev/null +++ b/ScopeEnvironment.cs @@ -0,0 +1,139 @@ +using System.Collections; +using System.Diagnostics.CodeAnalysis; + +namespace tlang +{ + public interface IScopeEnvironment : IEnumerable> + { + 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 items = new Dictionary(); + + 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> GetEnumerator() + { + return getVars().GetEnumerator(); + } + + private IEnumerable> 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 items = new Dictionary(); + + public IScopeEnvironment SubEnv => new SubEnvironment(this,this); + + public IScopeEnvironment RootEnv => this; + + public IEnumerator> 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); } + + } + +} \ No newline at end of file diff --git a/ScopeNode.cs b/ScopeNode.cs new file mode 100644 index 0000000..73d29fc --- /dev/null +++ b/ScopeNode.cs @@ -0,0 +1,17 @@ +namespace tlang +{ + public class ScopeNode : Node + { + public List Body {get;set;}= new List(); + 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; + } + } +} \ No newline at end of file diff --git a/SubtractNode.cs b/SubtractNode.cs new file mode 100644 index 0000000..77ef934 --- /dev/null +++ b/SubtractNode.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/TArray.cs b/TArray.cs new file mode 100644 index 0000000..14a6efd --- /dev/null +++ b/TArray.cs @@ -0,0 +1,12 @@ +namespace tlang +{ + public class TArray : TObject + { + public TArray() + { + + } + + public List Items {get;set;}=new List(); + } +} \ No newline at end of file diff --git a/TDictionary.cs b/TDictionary.cs new file mode 100644 index 0000000..efaa9dc --- /dev/null +++ b/TDictionary.cs @@ -0,0 +1,42 @@ +namespace tlang +{ + public class TDictionary : TObject + { + public TDictionary() + { + + } + + Dictionary items {get;set;}=new Dictionary(); + + 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); } + + + } +} \ No newline at end of file diff --git a/TInternalObject.cs b/TInternalObject.cs new file mode 100644 index 0000000..8486193 --- /dev/null +++ b/TInternalObject.cs @@ -0,0 +1,11 @@ +namespace tlang +{ + public class TInternalObject : TObject + { + public TInternalObject(object val) + { + Object=val; + } + public object Object {get;set;} + } +} \ No newline at end of file diff --git a/TMethod.cs b/TMethod.cs new file mode 100644 index 0000000..15f2eb8 --- /dev/null +++ b/TMethod.cs @@ -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 cb; + public TExternalMethod(Func func) + { + cb = func; + } + + public TObject Call(params TObject[] args) + { + return cb(args); + } + + + } + + public interface ICallable + { + TObject Call(params TObject[] args); + } +} \ No newline at end of file diff --git a/TNull.cs b/TNull.cs new file mode 100644 index 0000000..adc5dcf --- /dev/null +++ b/TNull.cs @@ -0,0 +1,10 @@ +namespace tlang +{ + public class TNull : TObject + { + public override string ToString() + { + return "null"; + } + } +} \ No newline at end of file diff --git a/TNumber.cs b/TNumber.cs new file mode 100644 index 0000000..87a46b8 --- /dev/null +++ b/TNumber.cs @@ -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(); + } + } + + +} \ No newline at end of file diff --git a/TObject.cs b/TObject.cs new file mode 100644 index 0000000..ee68f93 --- /dev/null +++ b/TObject.cs @@ -0,0 +1,9 @@ +namespace tlang +{ + public class TObject + { + + public static TObject Uninit => new TUninit(); + public static TObject Null => new TNull(); + } +} \ No newline at end of file diff --git a/TString.cs b/TString.cs new file mode 100644 index 0000000..f5ecbd6 --- /dev/null +++ b/TString.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/TUninit.cs b/TUninit.cs new file mode 100644 index 0000000..7b31b5d --- /dev/null +++ b/TUninit.cs @@ -0,0 +1,10 @@ +namespace tlang +{ + public class TUninit : TObject + { + public override string ToString() + { + return "undefined"; + } + } +} \ No newline at end of file diff --git a/file.tlang b/file.tlang new file mode 100644 index 0000000..4e686e2 --- /dev/null +++ b/file.tlang @@ -0,0 +1,7 @@ +/* + if(expression) expression else expression +*/ + +j = func() 42-43; + +printargs(j().abs()); \ No newline at end of file diff --git a/testString.tlang b/testString.tlang new file mode 100644 index 0000000..ce9eb0e --- /dev/null +++ b/testString.tlang @@ -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; +}; \ No newline at end of file diff --git a/tlang.csproj b/tlang.csproj new file mode 100644 index 0000000..d439800 --- /dev/null +++ b/tlang.csproj @@ -0,0 +1,10 @@ + + + + Exe + net7.0 + enable + enable + + +