├── test ├── testmodule.diana ├── testmeta.diana ├── test-exports.diana ├── main.diana ├── bf.diana ├── simple-bench.diana ├── test-feature.diana └── exhaustive-test.diana ├── test.sh ├── Diana ├── VM.cs ├── Config.cs ├── MethodImplOptionsCompat.cs ├── JITFunc.cs ├── Hash.cs ├── InternString.cs ├── Exceptions.cs ├── ByteASTLoader.cs ├── Data.cs.in ├── JITSupport.cs ├── ObjectSystem.Default.cs ├── MK.cs ├── CollectionExts.cs └── NumMethods.cs ├── requirements.txt ├── DianaScript.csproj ├── DianaScript.sln ├── LICENSE ├── Diana.Frontend ├── ParseException.cs ├── AntlrErrorListener.cs ├── OperatorResolver.cs └── DianaScriptParser.Interface.cs ├── Run.cs ├── DianaScript.Extended.tbnf ├── Diana.Generated ├── Methods.DInt.cs ├── Methods.DFloat.cs ├── Methods.DTuple.cs ├── Methods.DIterable.cs ├── Methods.DList.cs ├── Methods.DDict.cs └── Methods.DString.cs ├── codegen ├── MsgPack.lark ├── MsgPackGen.py ├── datatype_gen.py ├── MsgPackParser.lark ├── MsgPackParser.py ├── def.spec └── binding.spec ├── Diana.APIs ├── APIs.Autoconv.cs ├── APIs.Antlr4.cs └── APIs.cs ├── README.md ├── docs-CN.md ├── sigs-for-builtin-modules.json ├── DianaScript.tbnf ├── docs.md ├── .gitignore └── Diana.Metagen └── Metagen.cs /test/testmodule.diana: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | dotnet run test/main.diana -------------------------------------------------------------------------------- /Diana/VM.cs: -------------------------------------------------------------------------------- 1 | namespace Diana 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | lark-action 2 | pyrsistent 3 | jinja2 4 | -------------------------------------------------------------------------------- /Diana/Config.cs: -------------------------------------------------------------------------------- 1 | namespace Diana 2 | { 3 | public static class Config 4 | { 5 | 6 | public static bool SHOW_DOTNET_TRACE = true; 7 | 8 | } 9 | } -------------------------------------------------------------------------------- /test/testmeta.diana: -------------------------------------------------------------------------------- 1 | __SETMETA 0 "/home/thaut/Desktop/purescript-python/imps/src/Main.purs" 2 | x_main = log(__META 0:8:12 in "🍝") 3 | 4 | z = fun () 5 | return 3 6 | end 7 | 8 | z() -------------------------------------------------------------------------------- /test/test-exports.diana: -------------------------------------------------------------------------------- 1 | a = 1 2 | b = 2 3 | c = 3 4 | 5 | fun init() 6 | log("init is called at last!") 7 | end 8 | 9 | exports = { 10 | "a" : a, 11 | "b" : b 12 | } 13 | -------------------------------------------------------------------------------- /DianaScript.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5 5 | Exe 6 | true 7 | NUNITY;MY_DEBUG;CODEGEN 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/main.diana: -------------------------------------------------------------------------------- 1 | require("./simple-bench.diana") 2 | require("./exhaustive-test.diana") 3 | require("./testmeta.diana") 4 | require("./test-feature.diana") 5 | require("./testmeta.diana") 6 | require("./bf.diana") 7 | 8 | TestExports = require("./test-exports.diana") 9 | assert(("c" not in keys(TestExports)) == 1) 10 | 11 | # it's not a cross-platform way 12 | # TestExports2 = require("test/test-exports") 13 | # assert(TestExports2 == TestExports) 14 | -------------------------------------------------------------------------------- /Diana/MethodImplOptionsCompat.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | namespace Diana 3 | { 4 | public static class MethodImplOptionsCompat 5 | { 6 | public const MethodImplOptions AggressiveInlining = MethodImplOptions.AggressiveInlining; 7 | #if NUNITY 8 | public const MethodImplOptions AggressiveOptimization = MethodImplOptions.AggressiveOptimization; 9 | #else 10 | public const MethodImplOptions AggressiveOptimization = MethodImplOptions.AggressiveInlining; 11 | #endif 12 | } 13 | } -------------------------------------------------------------------------------- /test/bf.diana: -------------------------------------------------------------------------------- 1 | fun Op(op, val) 2 | {"op": op, "val": val} 3 | end 4 | 5 | 6 | fun Tape() 7 | self = {"tape": [0], "pos": 0} 8 | 9 | self.get = fun () 10 | self.tape.[self.pos] 11 | end 12 | self.inc = fun (x) 13 | self.tape.[self.pos] += x 14 | end 15 | self.move = fun (x) 16 | self.pos += x 17 | while self.pos >= len(self.tape) do 18 | List.extend( 19 | self.tape, 20 | Enum.rep(0, len(self.tape))) 21 | end 22 | end 23 | self 24 | end 25 | 26 | t = Tape() 27 | -------------------------------------------------------------------------------- /DianaScript.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DianaScript", "DianaScript.csproj", "{1A0614F7-4634-486C-9E62-A626C4EF3AF2}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {1A0614F7-4634-486C-9E62-A626C4EF3AF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {1A0614F7-4634-486C-9E62-A626C4EF3AF2}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {1A0614F7-4634-486C-9E62-A626C4EF3AF2}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {1A0614F7-4634-486C-9E62-A626C4EF3AF2}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | Copyright (c) 2021 thautwarm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 21 | OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Diana.Frontend/ParseException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace Diana.Frontend 5 | { 6 | 7 | /// 8 | /// An exception representing something going wrong during parsing. 9 | /// 10 | [Serializable] 11 | public sealed class ParseException : Exception 12 | { 13 | 14 | internal int LineNumber = 0; 15 | 16 | internal ParseException(string message) : base(message) { } 17 | 18 | internal static ParseException Make(Antlr4.Runtime.ParserRuleContext context, string message) 19 | { 20 | int line = context.Start.Line; 21 | 22 | // getting the text that has the issue inside 23 | int start = context.Start.StartIndex; 24 | int end = context.Stop.StopIndex; 25 | string body = context.Start.InputStream.GetText(new Antlr4.Runtime.Misc.Interval(start, end)); 26 | 27 | string theMessage = string.Format(CultureInfo.CurrentCulture, "Error on line {0}\n{1}\n{2}", line, body, message); 28 | 29 | var e = new ParseException(theMessage) 30 | { 31 | LineNumber = line, 32 | }; 33 | return e; 34 | } 35 | 36 | 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /Diana/JITFunc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace Diana 6 | { 7 | using NameSpace = Dictionary; 8 | using CPS = Func; 9 | public partial class DStaticFunc : DObj 10 | { 11 | public NameSpace ns; 12 | public Variable[] freevars; 13 | public Metadata co; 14 | public CPS body; 15 | 16 | [MethodImpl(MethodImplOptionsCompat.AggressiveOptimization | MethodImplOptionsCompat.AggressiveInlining)] 17 | public DObj __call__(params DObj[] args) 18 | { 19 | if (args.Length < co.narg) 20 | { 21 | throw new ArgumentException($"function {co.name} requires at least {co.narg} argument(s), got {args.Length}."); 22 | } 23 | Variable[] localvars; 24 | localvars = new Variable[co.nlocal]; 25 | for(int i = 0; i < args.Length; i++) 26 | { 27 | localvars[i] = new Variable { obj = args[i] }; 28 | } 29 | for(int i = args.Length; i < co.nlocal; i++) 30 | { 31 | localvars[i] = new Variable { obj = null }; 32 | } 33 | var ctx = new ExecContext(localvars, freevars, ns, co); 34 | return body(ctx); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Run.cs: -------------------------------------------------------------------------------- 1 | #if NUNITY 2 | using Diana; 3 | using System; 4 | using System.Linq; 5 | using System.Reflection; 6 | public static partial class MainClass 7 | { 8 | // Start is called before the first frame update 9 | 10 | public static void Main(string[] args) 11 | { 12 | 13 | // new Diana.Metagen.Metagen(Assembly.GetExecutingAssembly(), "Diana", "Diana.APIs/Generated"); 14 | Diana.ModularDiana modularDiana = new Diana.ModularDiana(); 15 | 16 | void ExecuteSourceFile(string path) 17 | { 18 | modularDiana.Exec(path); 19 | } 20 | 21 | 22 | if (args.Length != 0) 23 | { 24 | args.ToList().ForEach(ExecuteSourceFile); 25 | return; 26 | } 27 | 28 | var apis = new Diana.DianaScriptAPIs(); 29 | 30 | var globals = apis.InitGlobals(); 31 | while (true) 32 | { 33 | Console.Write("> "); 34 | String input = Console.ReadLine(); ; 35 | var ast = Diana.DianaScriptAPIs.Parse(input, "repl"); 36 | var ctx = MetaContext.Create("repl"); 37 | var initPos = ctx.currentPos; 38 | var runner = DianaScriptAPIs.compileModule(ast, "repl", "repl"); 39 | var res = runner(globals); 40 | Console.WriteLine(res.__repr__()); 41 | } 42 | } 43 | } 44 | #endif -------------------------------------------------------------------------------- /Diana/Hash.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Diana 5 | { 6 | public partial class DInt 7 | { 8 | public override int GetHashCode() 9 | { 10 | return value.GetHashCode(); 11 | } 12 | } 13 | 14 | public partial class DFloat 15 | { 16 | public override int GetHashCode() 17 | { 18 | return value.GetHashCode(); 19 | } 20 | } 21 | 22 | public partial class DString 23 | { 24 | public override int GetHashCode() 25 | { 26 | return value.GetHashCode(); 27 | } 28 | 29 | public override string ToString() 30 | { 31 | return value.ToString(); 32 | } 33 | } 34 | 35 | public partial class DTuple 36 | { 37 | public override int GetHashCode() 38 | { 39 | unchecked 40 | { 41 | int hash = 17; 42 | for (var i = 0; i < elts.Length; i++) 43 | hash = hash * 23 + elts[i].GetHashCode(); 44 | return hash; 45 | } 46 | } 47 | } 48 | 49 | public partial class DNone 50 | { 51 | public override int GetHashCode() 52 | { 53 | return 114514 ^ 267; 54 | } 55 | } 56 | 57 | public partial class DNative 58 | { 59 | public override int GetHashCode() 60 | { 61 | return value.GetHashCode(); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /DianaScript.Extended.tbnf: -------------------------------------------------------------------------------- 1 | %import "DianaScript.tbnf" 2 | 3 | typealias ast = ImmediateAST 4 | 5 | val mkOptionN: (token, list[ast]) -> (int, int, str, list[ast]) 6 | val mkDoOption: (ast) -> (int, int, str, list[ast]) 7 | val mkWorkflow: (token, str, str, list[(int, int, str, list[ast])]) -> ast 8 | val mkLet : (token, str, ast) -> ast 9 | val mkRaise: (token, ast) -> ast 10 | val mkMeta : (str, str, str, ast) -> ast 11 | val mkSetMeta: (token, str, str) -> ast 12 | val mkPipeline: (ast, list[ast]) -> ast 13 | val mkWorkflow: (token, str, ast, list[ast]) -> ast 14 | val mkOption: (token, str, list[ast]) -> ast 15 | 16 | stmt : "raise" expr { mkRaise($1, $2) } 17 | | "__SETMETA" { mkSetMeta($1, $2.Text, $3.Text) } 18 | | "__META" ":" ":" "do" stmt { mkMeta($2.Text, $4.Text, $6.Text, $8) } 19 | | line_wrap["begin"] block line_wrap["end"] { mkBlock($1, $2) } 20 | 21 | 22 | option : nullable[seplist[",", expr]] { mkOption($1, $1.Text, $2) } 23 | 24 | expr : "__META" ":" ":" "in" expr { mkMeta($2.Text, $4.Text, $6.Text, $8) } 25 | | or_expr list[pipe] { mkPipeline($1, $2) } 26 | | "{" filter[option, or_[";", newline]] "}" { mkWorkflow($1, "", mkVar($1, $1.Text), $3) } 27 | | "as" "{" filter[option, or_[";", newline]] "}" { mkWorkflow($1, $3.Text, mkVar($1, $1.Text), $5) } 28 | 29 | pipe : line_wrap["|>"] or_expr { $2 } -------------------------------------------------------------------------------- /Diana.Generated/Methods.DInt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Diana 4 | { 5 | public partial class DInt 6 | { 7 | public string Classname => "Int"; 8 | public static DModule module_instance {get; private set;} 9 | public static DObj bind_get_max(DObj[] _args) // bind cls prop 10 | { 11 | var nargs = _args.Length; 12 | if (nargs != 0) 13 | throw new ArgumentException($"accessing Int.get_max; needs 0 arguments, got {nargs}."); 14 | var ret = Int64.MaxValue; 15 | return MK.create(ret); } 16 | public static DObj bind_get_min(DObj[] _args) // bind cls prop 17 | { 18 | var nargs = _args.Length; 19 | if (nargs != 0) 20 | throw new ArgumentException($"accessing Int.get_min; needs 0 arguments, got {nargs}."); 21 | var ret = Int64.MinValue; 22 | return MK.create(ret); } 23 | public static DObj bind_of(DObj[] _args) // bind method 24 | { 25 | var nargs = _args.Length; 26 | if (nargs != 1) 27 | throw new ArgumentException($"calling Int.of; needs at least (1) arguments, got {nargs}."); 28 | var _arg0 = MK.unbox(THint.val, _args[0]); 29 | { 30 | var _return = TypeConversion.toInt(_arg0); 31 | return MK.create(_return); 32 | } 33 | throw new ArgumentException($"call Int.of; needs at most (1) arguments, got {nargs}."); 34 | } 35 | static DInt() 36 | { 37 | module_instance = new DModule("Int"); 38 | module_instance.fields.Add("get_max", MK.FuncN("Int.get_max", bind_get_max)); 39 | module_instance.fields.Add("get_min", MK.FuncN("Int.get_min", bind_get_min)); 40 | module_instance.fields.Add("of", MK.FuncN("Int.of", bind_of)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Diana.Generated/Methods.DFloat.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Diana 4 | { 5 | public partial class DFloat 6 | { 7 | public string Classname => "Num"; 8 | public static DModule module_instance {get; private set;} 9 | public static DObj bind_get_max(DObj[] _args) // bind cls prop 10 | { 11 | var nargs = _args.Length; 12 | if (nargs != 0) 13 | throw new ArgumentException($"accessing Num.get_max; needs 0 arguments, got {nargs}."); 14 | var ret = Single.MaxValue; 15 | return MK.create(ret); } 16 | public static DObj bind_get_min(DObj[] _args) // bind cls prop 17 | { 18 | var nargs = _args.Length; 19 | if (nargs != 0) 20 | throw new ArgumentException($"accessing Num.get_min; needs 0 arguments, got {nargs}."); 21 | var ret = Single.MinValue; 22 | return MK.create(ret); } 23 | public static DObj bind_of(DObj[] _args) // bind method 24 | { 25 | var nargs = _args.Length; 26 | if (nargs != 1) 27 | throw new ArgumentException($"calling Num.of; needs at least (1) arguments, got {nargs}."); 28 | var _arg0 = MK.unbox(THint.val, _args[0]); 29 | { 30 | var _return = TypeConversion.toFloat(_arg0); 31 | return MK.create(_return); 32 | } 33 | throw new ArgumentException($"call Num.of; needs at most (1) arguments, got {nargs}."); 34 | } 35 | static DFloat() 36 | { 37 | module_instance = new DModule("Num"); 38 | module_instance.fields.Add("get_max", MK.FuncN("Num.get_max", bind_get_max)); 39 | module_instance.fields.Add("get_min", MK.FuncN("Num.get_min", bind_get_min)); 40 | module_instance.fields.Add("of", MK.FuncN("Num.of", bind_of)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Diana/InternString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Diana 5 | { 6 | public static class InternStringExts 7 | { 8 | 9 | public static InternString toIntern(this string s) 10 | { 11 | return InternString.fromString(s); 12 | } 13 | 14 | } 15 | public struct InternString : IEquatable, IComparable, DObj 16 | { 17 | public string Classname => "symbol"; 18 | static Dictionary strToId = new Dictionary(); 19 | static Dictionary idToStr = new Dictionary(); 20 | int identity; 21 | public int CompareTo(InternString other) => identity.CompareTo(other.identity); 22 | 23 | public bool Equals(InternString other) => identity == other.identity; 24 | 25 | public override string ToString() => idToStr[identity]; 26 | public static InternString fromString(string s) 27 | { 28 | if (strToId.TryGetValue(s, out var id)) 29 | { 30 | return id; 31 | } 32 | id = new InternString { identity = strToId.Count }; 33 | strToId[s] = id; 34 | idToStr[id.identity] = s; 35 | 36 | return id; 37 | } 38 | 39 | public bool __eq__(DObj o) => o is InternString s && identity == s.identity; 40 | public bool __lt__(DObj o) => o is InternString s && identity < s.identity; 41 | 42 | public string __str__() => ":"+ToString(); 43 | 44 | public override int GetHashCode() 45 | { 46 | return identity.GetHashCode() ^ 47; 47 | } 48 | 49 | } 50 | } -------------------------------------------------------------------------------- /codegen/MsgPack.lark: -------------------------------------------------------------------------------- 1 | %% 2 | from __future__ import annotations 3 | %% 4 | 5 | %mkrepl 6 | name : TNAME -> str($1) 7 | 8 | list{e} : e -> [$1] 9 | | list{e} e -> append($1, $2) 10 | 11 | seplist{sep, e} : e -> [$1] 12 | | seplist{sep, e} sep e -> append($1, $3) 13 | 14 | nullable{seq} : -> [] 15 | | seq -> $1 16 | 17 | 18 | %% 19 | 20 | from dataclasses import dataclass, replace 21 | from pyrsistent import PVector, pvector 22 | 23 | def append(self, x): 24 | self.append(x) 25 | return self 26 | 27 | @dataclass(frozen=True) 28 | class TArr: 29 | eltype : Type 30 | 31 | @dataclass(frozen=True) 32 | class TTup: 33 | eltypes : PVector[Type] 34 | 35 | @dataclass(frozen=True) 36 | class TName: 37 | name: str 38 | 39 | 40 | @dataclass(frozen=True) 41 | class Field: 42 | type: Type 43 | name: str 44 | 45 | Type = TName | TTup | TArr 46 | 47 | @dataclass(frozen=True) 48 | class Def: 49 | name: str 50 | fields: PVector[Field] = pvector([]) 51 | tag: int = -1 52 | 53 | def __iter__(self): 54 | yield from self.fields 55 | def __len__(self): 56 | return len(self.fields) 57 | 58 | tag_counter = [0] 59 | 60 | def next_tag(): 61 | x = tag_counter[0] 62 | tag_counter[0] += 1 63 | return x 64 | %% 65 | 66 | type : "(" seplist{",", type} ")" -> TTup(pvector($2)) 67 | | type "[" "]" -> TArr($1) 68 | | name -> TName($1) 69 | 70 | field : name ":" type -> Field($3, $1) 71 | | type name -> Field($1, $2) 72 | 73 | topl : name "(" nullable{seplist{",", field}} ")" -> \ 74 | Def(name= $1, fields=$3, tag=next_tag()) 75 | 76 | start : list{topl} -> $1 77 | 78 | 79 | %import common.WS 80 | %import common.ESCAPED_STRING 81 | %import common.LETTER 82 | %import common.DIGIT 83 | %ignore WS 84 | %ignore COMMENT 85 | COMMENT: /\s*/ "//" /[^\n]/* 86 | TNAME: ("_"|"$"|LETTER) ("_"|"$"|LETTER|DIGIT)* 87 | ESCAPED_CODE : /\[%[^%]*?%\]/ -------------------------------------------------------------------------------- /Diana.Generated/Methods.DTuple.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq;using System.Collections.Generic; 3 | namespace Diana 4 | { 5 | public partial class DTuple 6 | { 7 | public string Classname => "Tuple"; 8 | public static DModule module_instance {get; private set;} 9 | public static DObj bind_len(DObj[] _args) // bind `this` prop 10 | { 11 | var nargs = _args.Length; 12 | if (nargs != 1) 13 | throw new ArgumentException($"accessing Tuple.len; needs only 1 argument, got {nargs}."); 14 | var arg = _args[0]; 15 | var ret = MK.unbox(THint.val, arg).Length; 16 | return MK.create(ret); 17 | } 18 | public static DObj bind_of(DObj[] _args) // bind method 19 | { 20 | var nargs = _args.Length; 21 | if (nargs != 1) 22 | throw new ArgumentException($"calling Tuple.of; needs at least (1) arguments, got {nargs}."); 23 | var _arg0 = MK.unbox(THint>.val, _args[0]); 24 | { 25 | var _return = _arg0.ToArray(); 26 | return MK.create(_return); 27 | } 28 | throw new ArgumentException($"call Tuple.of; needs at most (1) arguments, got {nargs}."); 29 | } 30 | public static DObj bind_forkey(DObj[] _args) // bind method 31 | { 32 | var nargs = _args.Length; 33 | if (nargs != 2) 34 | throw new ArgumentException($"calling Tuple.forkey; needs at least (2) arguments, got {nargs}."); 35 | var _arg0 = MK.unbox(THint.val, _args[0]); 36 | var _arg1 = MK.unbox(THint.val, _args[1]); 37 | { 38 | _arg0.ForEachIndex_(_arg1); 39 | return MK.None(); 40 | } 41 | throw new ArgumentException($"call Tuple.forkey; needs at most (2) arguments, got {nargs}."); 42 | } 43 | static DTuple() 44 | { 45 | module_instance = new DModule("Tuple"); 46 | module_instance.fields.Add("len", MK.FuncN("Tuple.len", bind_len)); 47 | module_instance.fields.Add("of", MK.FuncN("Tuple.of", bind_of)); 48 | module_instance.fields.Add("forkey", MK.FuncN("Tuple.forkey", bind_forkey)); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/simple-bench.diana: -------------------------------------------------------------------------------- 1 | x = 1 2 | log(x) 3 | 4 | fun f(x) 5 | return x + x 6 | end 7 | 8 | log(2 + f(1)) 9 | 10 | 11 | if 1 > 2 then 12 | log("2") 13 | else 14 | log("3") 15 | end 16 | 17 | fun fact(x) 18 | if x < 1 then 19 | log("ret") 20 | return 1 21 | else 22 | r = x * fact(x - 1) 23 | log(r, "<- ret") 24 | return r 25 | end 26 | end 27 | 28 | log(f(10)) 29 | 30 | x = 10 31 | log("hhh") 32 | 33 | if x < 5 then 34 | log(1) 35 | else 36 | log(x) 37 | end 38 | 39 | 40 | log("y", fact(5)) 41 | log([1, 2, 3]) 42 | 43 | log([1, 2, 3].[0]) 44 | 45 | if x + 1 == 2 then 46 | else 47 | log(3) 48 | end 49 | 50 | fun g() 51 | for i in [1, 2, 3, 4] do 52 | log(i) 53 | end 54 | end 55 | 56 | g() 57 | 58 | log(Int.of("233")) 59 | 60 | x = time() 61 | 62 | fun test() 63 | var x 64 | while x < 10000000 do 65 | x = x + 1 66 | end 67 | end 68 | 69 | log((time() - x)) 70 | 71 | log((time() - time())) 72 | log((time() - time())) 73 | log((time() - time())) 74 | log((time() - time())) 75 | log((time() - time())) 76 | log((time() - time())) 77 | log((time() - time())) 78 | log((time() - time())) 79 | log((time() - time())) 80 | log((time() - time())) 81 | log((time() - time())) 82 | log("aaa") 83 | 84 | 85 | fun test2() 86 | var localvariable 87 | var x = 0 88 | for localvariable in Enum.range(10000000) do 89 | x += 1 90 | # while localvariable < 10000000 do 91 | # localvariable = localvariable + 1 92 | end 93 | return x 94 | end 95 | 96 | 97 | fun benchfunc(f) 98 | var x 99 | var x = time() 100 | r = f() 101 | span = time() - x 102 | log("time elapsed for " + Str.of(f) + ":", span, "result:" + r) 103 | end 104 | 105 | benchfunc(test2) 106 | benchfunc(test2) 107 | benchfunc(test2) 108 | 109 | if 0 > 1000 then 110 | log("写写嘛, 没事的!") 111 | else 112 | log("皮套狗能不能爬?呕") 113 | end 114 | 115 | 116 | -------------------------------------------------------------------------------- /Diana.APIs/APIs.Autoconv.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Diana 4 | { 5 | [Metagen.Converter] 6 | public static class BuiltinConverters 7 | { 8 | [Metagen.Converter] 9 | public static int object_to_int(DObj o) 10 | { 11 | return (int) ((DInt) o).value; 12 | } 13 | 14 | [Metagen.Converter] 15 | public static long object_to_long(DObj o) 16 | { 17 | return ((DInt) o).value; 18 | } 19 | 20 | [Metagen.Converter] 21 | public static bool object_to_bool(DObj o) 22 | { 23 | return ((DInt) o).value != 0; 24 | } 25 | 26 | [Metagen.Converter] 27 | public static DObj bool_to_object(bool b) 28 | { 29 | return MK.Int(b); 30 | } 31 | 32 | [Metagen.Converter] 33 | public static DObj int_to_object(int i) 34 | { 35 | return MK.Int(i); 36 | } 37 | 38 | [Metagen.Converter] 39 | public static DObj long_to_object(long i) 40 | { 41 | return MK.Int(i); 42 | } 43 | 44 | [Metagen.Converter] 45 | public static DObj string_to_object(string s) 46 | { 47 | return MK.String(s); 48 | } 49 | 50 | [Metagen.Converter] 51 | public static string object_to_string(DObj o) 52 | { 53 | return (string) (DString) o; 54 | } 55 | 56 | [Metagen.Converter] 57 | public static float object_to_float(DObj o) 58 | { 59 | return (float) (DFloat) o; 60 | } 61 | 62 | [Metagen.Converter] 63 | public static DObj float_to_object(float f) 64 | { 65 | return MK.Float(f); 66 | } 67 | 68 | [Metagen.Converter] 69 | public static DObj double_to_object(double f) 70 | { 71 | return MK.Float((float) f); 72 | } 73 | 74 | [Metagen.Converter] 75 | public static double object_to_double(DObj o) 76 | { 77 | return (double) ((DFloat) o).value; 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /Diana.APIs/APIs.Antlr4.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System; 4 | using System.Linq; 5 | using Diana.Frontend; 6 | using Antlr4.Runtime; 7 | using Antlr4.Runtime.Tree; 8 | 9 | namespace Diana 10 | { 11 | public partial class DianaScriptAPIs 12 | { 13 | public static ImmediateAST Parse(string path) 14 | { 15 | ICharStream stream = CharStreams.fromPath(path); 16 | DianaScriptLexer lexer = new DianaScriptLexer(stream); 17 | ITokenStream tokens = new CommonTokenStream(lexer); 18 | var parser = new DianaScriptParser(tokens); 19 | parser.RemoveErrorListeners(); 20 | parser.AddErrorListener(ParserErrorListener.Instance); 21 | lexer.RemoveErrorListeners(); 22 | lexer.AddErrorListener(LexerErrorListener.Instance); 23 | try 24 | { 25 | var result = parser.start().result.ToArray(); 26 | return Block.make(result, 0, 0); 27 | } 28 | catch (ParseException e) 29 | { 30 | throw new ParseException($"parsing {path} failed:\n {e.Message}"); 31 | } 32 | } 33 | 34 | public static ImmediateAST Parse(string content, string path) 35 | { 36 | ICharStream stream = CharStreams.fromString(content); 37 | DianaScriptLexer lexer = new DianaScriptLexer(stream); 38 | ITokenStream tokens = new CommonTokenStream(lexer); 39 | var parser = new DianaScriptParser(tokens); 40 | parser.RemoveErrorListeners(); 41 | parser.AddErrorListener(ParserErrorListener.Instance); 42 | lexer.RemoveErrorListeners(); 43 | lexer.AddErrorListener(LexerErrorListener.Instance); 44 | try 45 | { 46 | var result = parser.start().result.ToArray(); 47 | return Block.make(result, 0, 0); 48 | } 49 | catch (ParseException e) 50 | { 51 | throw new ParseException($"parsing {path} failed:\n {e.Message}"); 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /codegen/MsgPackGen.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from jinja2 import Environment 3 | from jinja2.loaders import BaseLoader 4 | from MsgPackParser import parser, TName, TArr, TTup 5 | from pathlib import Path 6 | import textwrap 7 | 8 | env = Environment( 9 | loader = BaseLoader(), 10 | extensions=['jinja2.ext.do'], 11 | trim_blocks=True, 12 | lstrip_blocks=True 13 | ) 14 | 15 | # import prettyprinter 16 | # prettyprinter.install_extras(["dataclasses"]) 17 | 18 | defs = parser.parse(Path(__file__).with_name("def.spec").open().read()) 19 | 20 | def find_paths(p: Path): 21 | if not p.is_dir(): 22 | if p.suffix == ".in": 23 | yield p 24 | else: 25 | for i in p.iterdir(): 26 | if i == p: 27 | continue 28 | yield from find_paths(i) 29 | 30 | 31 | py_map = { 32 | 'Tuple': 'tuple', 33 | 'string': 'str' 34 | } 35 | 36 | def PY_filter(x) -> str: 37 | if isinstance(x, TName): 38 | return py_map.get(x.name, x.name) 39 | elif isinstance(x, TTup): 40 | return 'tuple[{}]'.format(', '.join(map(PY_filter, x.eltypes))) 41 | else: 42 | assert isinstance(x, TArr) 43 | return 'list[{}]'.format(PY_filter(x.eltype)) 44 | 45 | def NET_filter(x) -> str: 46 | if isinstance(x, TName): 47 | return x.name 48 | elif isinstance(x, TTup): 49 | return '({})'.format(', '.join(map(NET_filter, x.eltypes))) 50 | else: 51 | assert isinstance(x, TArr), x 52 | return '{}[]'.format(NET_filter(x.eltype)) 53 | 54 | env.filters['PY'] = PY_filter 55 | env.filters['NET'] = NET_filter 56 | 57 | dataclass_names = {defi.name for defi in defs} 58 | 59 | def assert_(x): 60 | assert x 61 | 62 | import builtins 63 | 64 | ARR_TYPES = {TName("string")} 65 | 66 | namespace = {**builtins.__dict__, **globals()} 67 | for FROM, TO in [ 68 | (path, path.with_suffix("")) for path in find_paths(Path(__file__).parent.parent) 69 | ]: 70 | try: 71 | template = env.from_string(FROM.open(encoding='utf8').read()) 72 | s = template.render(**namespace) 73 | TO.open('w', encoding='utf8').write(s) 74 | print(TO, "written") 75 | except: 76 | print(FROM) 77 | raise -------------------------------------------------------------------------------- /Diana/Exceptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Collections.Generic; 4 | 5 | namespace Diana 6 | { 7 | 8 | public class DianaVMError : Exception 9 | { 10 | public Exception e; 11 | 12 | public SourcePos pos; 13 | 14 | public DianaVMError(Exception e, SourcePos pos) : base() 15 | { 16 | this.e = e; 17 | this.pos = pos; 18 | } 19 | 20 | 21 | public override string StackTrace => get_stack_trace(); 22 | 23 | string get_stack_trace() 24 | { 25 | return $"at {pos.filename}:{pos.line}:{pos.col}: " + "\n" + e.Message 26 | + (Config.SHOW_DOTNET_TRACE ? ("\n" + e.StackTrace) : "") 27 | ; 28 | } 29 | } 30 | 31 | public class LocatedError : Exception 32 | { 33 | SourcePos pos; 34 | Exception e; 35 | string kind; 36 | public LocatedError(Exception e, string kind, SourcePos pos) : base() 37 | { 38 | this.pos = pos; 39 | this.e = e; 40 | this.kind = kind; 41 | } 42 | 43 | public override string StackTrace => get_stack_trace(); 44 | 45 | string get_stack_trace() 46 | { 47 | return $" {kind} at {pos.filename}:{pos.line}:{pos.col}: " 48 | + "\n " + e.Message 49 | + "\n " + e.StackTrace; 50 | } 51 | 52 | 53 | } 54 | 55 | public class NameError : Exception 56 | { 57 | public NameError(string s) : base(s) 58 | { 59 | } 60 | 61 | public NameError(string kind, string s) : base($"{kind} variable {s} not found") 62 | { 63 | } 64 | } 65 | 66 | public class AttributeError : Exception 67 | { 68 | public AttributeError(string s) : base(s) 69 | { 70 | } 71 | } 72 | 73 | public class ValueError : Exception 74 | { 75 | public ValueError(string s) : base(s) 76 | { 77 | } 78 | } 79 | 80 | public class TypeError : Exception 81 | { 82 | public TypeError(string s) : base(s) 83 | { 84 | } 85 | } 86 | 87 | public class AssertionError : Exception 88 | { 89 | public AssertionError(string s) : base(s) 90 | { 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /codegen/datatype_gen.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | 4 | def find_paths(p: Path): 5 | if not p.is_dir(): 6 | if p.suffix == ".gen": 7 | yield p 8 | else: 9 | for i in p.iterdir(): 10 | if i == p: 11 | continue 12 | yield from find_paths(i) 13 | 14 | 15 | for FROM, TO in [ 16 | (path, path.with_suffix(".py")) for path in find_paths(Path(__file__).parent.parent) 17 | ]: 18 | with FROM.open() as f: 19 | text = f.read() 20 | 21 | defs = [[e.strip() for e in i.strip().split()] for i in text.split(";")] 22 | code = [ 23 | "from __future__ import annotations", 24 | "from enum import Enum, auto as _auto", 25 | "import typing", 26 | "from dataclasses import dataclass", 27 | ] 28 | defs = list(filter(None, defs)) 29 | datatypes = [] 30 | 31 | for each in defs: 32 | code.append("") 33 | code.append("") 34 | 35 | head, *each = each 36 | if head == "typevar": 37 | var, *args = each 38 | cov = "" 39 | if args: 40 | cov = "bound=" + " | ".join(map(repr, args)) 41 | code.append(f"{var} = typing.TypeVar({var!r}, {cov})") 42 | if head == "import": 43 | code.append(f"from {each[0]} import *") 44 | elif head == "enum": 45 | name, *variants = each 46 | code.append(f"class {name}(Enum):") 47 | for v in variants: 48 | code.append(f" {v} = _auto()") 49 | else: 50 | code.append(" pass") 51 | elif head == "data": 52 | name, *fields = each 53 | datatypes.append(name) 54 | code.append("@dataclass") 55 | code.append(f"class {name}:") 56 | if fields: 57 | for v in fields: 58 | code.append(" " + v) 59 | code.append(" " + "loc: tuple[int, int] | None = None") 60 | code.append("\n") 61 | code.append(" " + "def __or__(self, loc):") 62 | code.append(" " + " self.loc = loc") 63 | code.append(" " + " return self") 64 | 65 | code.append("\n") 66 | 67 | code.append(f'{FROM.with_suffix("").name.capitalize()} = {" | ".join(datatypes)}') 68 | 69 | with TO.open("w") as f: 70 | f.write("\n".join(code)) -------------------------------------------------------------------------------- /codegen/MsgPackParser.lark: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | name : TNAME -> name_0 7 | 8 | list{e} : e -> list_0 9 | | list{e} e -> list_1 10 | 11 | seplist{sep, e} : e -> seplist_0 12 | | seplist{sep, e} sep e -> seplist_1 13 | 14 | nullable{seq} : -> nullable_0 15 | | seq -> nullable_1 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | type : "(" seplist{",", type} ")" -> type_0 67 | | type "[" "]" -> type_1 68 | | name -> type_2 69 | 70 | field : name ":" type -> field_0 71 | | type name -> field_1 72 | 73 | topl : name "(" nullable{seplist{",", field}} ")" -> topl_0 74 | 75 | start : list{topl} -> start_0 76 | 77 | 78 | %import common.WS 79 | %import common.ESCAPED_STRING 80 | %import common.LETTER 81 | %import common.DIGIT 82 | %ignore WS 83 | %ignore COMMENT 84 | COMMENT: /\s*/ "//" /[^\n]/* 85 | TNAME: ("_"|"$"|LETTER) ("_"|"$"|LETTER|DIGIT)* 86 | ESCAPED_CODE : /\[%[^%]*?%\]/ -------------------------------------------------------------------------------- /test/test-feature.diana: -------------------------------------------------------------------------------- 1 | print = log 2 | fun assert_and_print(test, msg) 3 | a = assert(test, msg) 4 | assert(a == None) 5 | print("passed: ", msg) 6 | end 7 | 8 | log({1: 2, "3": 4}) 9 | log({1: 2, (1, 2): 3}) 10 | 11 | c = (1, 2) 12 | d = {1: 2, c: 3} 13 | 14 | log(d.[1]) 15 | 16 | log(d.[c]) 17 | 18 | log(d.[(1,2)]) 19 | 20 | 21 | if 5 in d then 22 | log("有病吧?(failed)") 23 | else 24 | log("我似楞啊?(success)") 25 | end 26 | 27 | 28 | if 5 not in {1: 2, "5": []} then 29 | log("正确的") 30 | elif 2 ** 4 in [17] then 31 | log("错误的") 32 | end 33 | 34 | z = if 10 in {1: 2, "5": []} then 35 | log("错误的") 36 | elif 2 ** 4 in [17] then 37 | log("错误的") 38 | end 39 | 40 | if (z == None) then 41 | log("正确的") 42 | else 43 | log("错误的") 44 | end 45 | 46 | 47 | 48 | k = {1 : 2} 49 | z = [None] 50 | Dict.search(k, 1, z) 51 | log(z) 52 | 53 | z = [None] 54 | log(Dict.search(k, 10, z)) 55 | log(z) 56 | 57 | assert(z == [None]) 58 | assert(not isdefined("_")) 59 | 60 | 61 | log({"a" : 5 }) 62 | 63 | log(Num.of("1.2")) 64 | log(typeof(Num.of(12)) == "Num") 65 | 66 | log(Int.of(1.2)) 67 | 68 | 69 | var x 70 | 71 | x = 2 72 | 73 | log(x) 74 | 75 | 76 | {:a: 2} 77 | 78 | ☆ = 1 79 | 80 | assert(☆ == 1) 81 | 82 | 83 | ☆☆ = 2 84 | assert(☆☆ != 1) 85 | 86 | log(1 87 | and 2, "'and' operator line continuation") 88 | 89 | log(1 90 | or 2, "'or' operator line continuation") 91 | 92 | 93 | fun test_cell(x) 94 | fun set(v) 95 | x = v 96 | end 97 | 98 | fun get() 99 | x 100 | end 101 | (set, get) 102 | end 103 | 104 | gs = test_cell(1) 105 | gset = gs.[0] 106 | gget = gs.[1] 107 | 108 | assert_and_print(gget() == 1, "test cell: get 1") 109 | gset(2) 110 | assert_and_print(gget() == 2, "test cell: get 2") 111 | gset(3) 112 | assert_and_print(gget() == 3, "test cell: get 3") 113 | 114 | 115 | builder = { 116 | "start": fun () 117 | log("started!") 118 | end, 119 | "do_": (self, x) -> log("do" + Str.of(x)), 120 | "finish": (self) -> log("finished!") 121 | } 122 | 123 | builder { 124 | do_ 1 125 | do_ 2 126 | do_ 3 127 | } 128 | 129 | builder = { 130 | "start": fun() 131 | x = {} 132 | return x 133 | end, 134 | "yield": (self, x) -> log("yield " + Str.of(x)), 135 | "finish": (self) -> (), 136 | "reason": (self) -> log("reason!") 137 | } 138 | 139 | 140 | 141 | builder as bb { 142 | reason 143 | yield 1 144 | yield bb 145 | } 146 | 147 | (a, b, (c, d, (e, ))) = (1, 2, (3, 4, (5, ))) 148 | 149 | assert_and_print(a == 1 and b == 2 and c == 3 and d == 4 and e == 5, "global_unpack") 150 | 151 | var x = 1 152 | 153 | fun () 154 | var a, b, c, d, e 155 | (a, b, (c, d, (e, ))) = (1, 2, (3, 4, (5, ))) 156 | assert_and_print(a == 1 and b == 2 and c == 3 and d == 4 and e == 5, "local_unpack") 157 | end() 158 | 159 | 160 | uuuuuu = "a" 161 | 162 | fun () 163 | var uuuuuu = "b" 164 | end 165 | 166 | assert_and_print(uuuuuu == "a", "not polluted") -------------------------------------------------------------------------------- /codegen/MsgPackParser.py: -------------------------------------------------------------------------------- 1 | # Generated from lark-action. 2 | 3 | 4 | from __future__ import annotations 5 | 6 | if '_get_location' not in globals(): 7 | def _get_location(token): 8 | return (token.line, token.column) 9 | 10 | if '_get_value' not in globals(): 11 | def _get_value(token): 12 | return token.value 13 | 14 | 15 | 16 | from dataclasses import dataclass, replace 17 | from pyrsistent import PVector, pvector 18 | 19 | def append(self, x): 20 | self.append(x) 21 | return self 22 | 23 | @dataclass(frozen=True) 24 | class TArr: 25 | eltype : Type 26 | 27 | @dataclass(frozen=True) 28 | class TTup: 29 | eltypes : PVector[Type] 30 | 31 | @dataclass(frozen=True) 32 | class TName: 33 | name: str 34 | 35 | 36 | @dataclass(frozen=True) 37 | class Field: 38 | type: Type 39 | name: str 40 | 41 | Type = TName | TTup | TArr 42 | 43 | @dataclass(frozen=True) 44 | class Def: 45 | name: str 46 | fields: PVector[Field] = pvector([]) 47 | tag: int = -1 48 | 49 | def __iter__(self): 50 | yield from self.fields 51 | def __len__(self): 52 | return len(self.fields) 53 | 54 | tag_counter = [0] 55 | 56 | def next_tag(): 57 | x = tag_counter[0] 58 | tag_counter[0] += 1 59 | return x 60 | 61 | 62 | from MsgPackParser_raw import Transformer, Lark_StandAlone, Tree 63 | class MsgPackParser_Transformer(Transformer): 64 | 65 | def name_0(self, __args): 66 | return str(__args[1-1]) 67 | def list_0(self, __args): 68 | return [__args[1-1]] 69 | def list_1(self, __args): 70 | return append(__args[1-1], __args[2-1]) 71 | def seplist_0(self, __args): 72 | return [__args[1-1]] 73 | def seplist_1(self, __args): 74 | return append(__args[1-1], __args[3-1]) 75 | def nullable_0(self, __args): 76 | return [] 77 | def nullable_1(self, __args): 78 | return __args[1-1] 79 | def type_0(self, __args): 80 | return TTup(pvector(__args[2-1])) 81 | def type_1(self, __args): 82 | return TArr(__args[1-1]) 83 | def type_2(self, __args): 84 | return TName(__args[1-1]) 85 | def field_0(self, __args): 86 | return Field(__args[3-1], __args[1-1]) 87 | def field_1(self, __args): 88 | return Field(__args[1-1], __args[2-1]) 89 | def topl_0(self, __args): 90 | return Def(name= __args[1-1], fields=__args[3-1], tag=next_tag()) 91 | def start_0(self, __args): 92 | return __args[1-1] 93 | 94 | 95 | parser = Lark_StandAlone(transformer=MsgPackParser_Transformer()) 96 | if __name__ == '__main__': 97 | 98 | import prettyprinter 99 | prettyprinter.install_extras(["dataclasses"]) 100 | while True: 101 | print("input q and exit.") 102 | source = input("> ") 103 | if source.strip() == "q": 104 | break 105 | if not source.strip(): 106 | continue 107 | res = parser.parse(source) 108 | if not isinstance(res, Tree): 109 | prettyprinter.pprint(res) 110 | else: 111 | print(res) 112 | 113 | -------------------------------------------------------------------------------- /Diana/ByteASTLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | 5 | namespace Diana 6 | { 7 | public static class ConstPoolTag 8 | { 9 | public const byte SpecialTag = 0b01 << 7; 10 | 11 | public const byte Int = 0; 12 | public const byte Float = 1; 13 | public const byte Str = 2; 14 | 15 | 16 | public const byte Dict = 3; 17 | public const byte Set = 4; 18 | public const byte List = 5; 19 | public const byte Tuple = 6; 20 | } 21 | 22 | 23 | public partial class ByteASTLoader 24 | { 25 | private BinaryReader binaryReader; 26 | private byte[] cache_4byte = new byte[4]; 27 | private byte[] cache_32byte = new byte[32]; 28 | 29 | public ByteASTLoader(FileStream fs) 30 | { 31 | binaryReader = new BinaryReader(fs); 32 | } 33 | 34 | public ByteASTLoader(string path) 35 | { 36 | var fs = File.Open(path, FileMode.Open); 37 | binaryReader = new BinaryReader(fs); 38 | } 39 | 40 | 41 | private DObj Read(THint _) => throw new NotImplementedException("cannot deserialize external dobjects!"); 42 | 43 | private (int, int, string, ImmediateAST[]) Read(THint<(int, int, string, ImmediateAST[])> _) => throw new NotImplementedException(); 44 | 45 | public (ImmediateAST, ImmediateAST) Read(THint<(ImmediateAST, ImmediateAST)> _) => 46 | (ReadImmediateAST(), ReadImmediateAST()); 47 | 48 | public (ImmediateAST, string) Read(THint<(ImmediateAST, string)> _) => 49 | (ReadImmediateAST(), ReadStr()); 50 | 51 | public (int, int) Read(THint<(int, int)> _) 52 | { 53 | return (ReadInt(), ReadInt()); 54 | } 55 | 56 | public string Read(THint _) 57 | { 58 | return ReadStr(); 59 | } 60 | 61 | public int Read(THint _) => ReadInt(); 62 | 63 | public Int64 Read(THint _) => ReadInt(); 64 | 65 | public int ReadTag() => binaryReader.ReadByte(); 66 | 67 | public int ReadInt() 68 | { 69 | var i = binaryReader.ReadInt32(); 70 | #if A_DBG 71 | Console.WriteLine($"parse integer: '{i}'"); 72 | #endif 73 | return i; 74 | } 75 | 76 | public float Read(THint _) => ReadFloat(); 77 | 78 | public float ReadFloat() 79 | { 80 | var f = binaryReader.ReadSingle(); 81 | #if A_DBG 82 | Console.WriteLine($"parse float: '{f}'"); 83 | #endif 84 | return f; 85 | } 86 | 87 | // public InternString Read(THint _) => ReadInternString(); 88 | 89 | public string Readstring() => ReadStr(); 90 | 91 | public string ReadStr() 92 | { 93 | var s = binaryReader.ReadString(); 94 | #if A_DBG 95 | Console.WriteLine($"parse string: '{s}'"); 96 | #endif 97 | return s; 98 | } 99 | 100 | public bool Read(THint _) => ReadBool(); 101 | 102 | public bool ReadBool() 103 | { 104 | return ReadInt() == 0 ? false : true; 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Powered by [Typed BNF](https://github.com/thautwarm/typed-bnf). 2 | 3 | ## diana script 4 | 5 | [![EN DOC](https://img.shields.io/badge/docs-v0.1-green.svg?style=flat)](https://github.com/thautwarm/DianaScript/blob/master/docs.md) [![CN DOC](https://img.shields.io/badge/文档-v0.1-green.svg?style=flat)](https://github.com/thautwarm/DianaScript/blob/master/docs-CN.md) 6 | 7 | A fast interpreter implemented in C#, shipped with a mininal but expressive scripting language called **Diana**. 8 | 9 | No DLR, No System.Reflection(.Emit), compatible to all Unity backends. 10 | 11 | Diana Script features at 12 | 13 | 1. fast execution time and startup time 14 | 2. simplicity(see docs for the concise cheat sheet) 15 | 3. easy [.NET interops](#dotnet-interops) 16 | 17 | Diana Script is as 0.5x fast as CPython(>2.5x faster than Jint), and expected to be **thread-safe**. 18 | 19 | ## Integration within Your Project(available to Unity env) 20 | 21 | ```C# 22 | using Diana; 23 | public static class YourApi 24 | { 25 | public static void ExecFromPath(string path) 26 | { 27 | var apis = new DianaScriptAPIs(); 28 | var globals = apis.InitGlobals(); 29 | 30 | var ast = DianaScriptAPIs.Parse(path); 31 | var exec = DianaScriptAPIs.compileModule(ast, path); 32 | exec(globals); 33 | } 34 | } 35 | ``` 36 | 37 | ## dotnet-interops 38 | 39 | 40 | ### Use `DObj` in .NET 41 | 42 | ```c# 43 | 44 | public void Do(DObj diana_object) 45 | { 46 | var i = (int) (DInt) diana_object; // if it's int 47 | var f = (float) (DFloat) diana_object; // if it's float 48 | var s = (string) (DString) diana_object; // it string 49 | 50 | if(diana_object.__bool__()) 51 | do_some; 52 | 53 | diana_object.__add__(diana_object); 54 | // diana_object.__sub__(diana_object); 55 | 56 | 57 | // use diana_object as callable 58 | if(diana_object.__call__(diana_object, diana_object, ...).__bool__()) 59 | { 60 | // ... 61 | } 62 | 63 | 64 | DObj int_obj = MK.Int(1000); 65 | DObj float_obj = MK.Float(15.0); 66 | DObj dict = MK.Dict( new Dictionary 67 | { 68 | { int_obj, float_obj }, 69 | { float_obj, int_obj }, 70 | }); 71 | } 72 | ``` 73 | 74 | ### Create Your Own `DObj` Classes 75 | 76 | 77 | ```C# 78 | using Diana; 79 | public record DMyClass(MyOwnClass o): DObj 80 | { 81 | public object Native => o; 82 | 83 | public bool __eq__(DObj other) => (other is DMyClass o_) && o_.Equals(o); 84 | 85 | public DObj __get__(DObj s) 86 | { 87 | var attr = (string) (DString) s; 88 | switch(attr) 89 | { 90 | case "mymethod": 91 | return MK.FuncN( args => o.mymethod(args[0], args[1], args[2]) ); 92 | case "myfield": 93 | // suppose it's an integer 94 | return MK.Int(o.myfield); 95 | case "myfield2": 96 | // can be any .NET object 97 | return MK.Wrap(o.myfield2); 98 | default: 99 | throw new InvalidOperationException( 100 | $"scripts are not allowed to access {attr}!" 101 | ); 102 | } 103 | } 104 | } 105 | ``` -------------------------------------------------------------------------------- /Diana.Frontend/AntlrErrorListener.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Antlr4.Runtime; 3 | using System.Text; 4 | using System.IO; 5 | using System.Globalization; 6 | 7 | namespace Diana.Frontend 8 | { 9 | internal sealed class LexerErrorListener : IAntlrErrorListener 10 | { 11 | private static readonly LexerErrorListener instance = new LexerErrorListener(); 12 | public static LexerErrorListener Instance => instance; 13 | 14 | public void SyntaxError(TextWriter output, IRecognizer recognizer, int offendingSymbol, int line, int charPositionInLine, string msg, RecognitionException e) 15 | { 16 | StringBuilder builder = new StringBuilder(); 17 | builder.Append($"Error on line {line} at position {charPositionInLine + 1}:"); 18 | builder.AppendLine(msg); 19 | 20 | throw new ParseException(builder.ToString()); 21 | 22 | } 23 | } 24 | 25 | internal sealed class ParserErrorListener : BaseErrorListener 26 | { 27 | private static readonly ParserErrorListener instance = new ParserErrorListener(); 28 | public static ParserErrorListener Instance => instance; 29 | 30 | public override void SyntaxError(System.IO.TextWriter output, IRecognizer recognizer, IToken offendingSymbol, int line, int charPositionInLine, string msg, RecognitionException e) 31 | { 32 | StringBuilder builder = new StringBuilder(); 33 | 34 | // the human readable message 35 | object[] format = new object[] { line, charPositionInLine + 1 }; 36 | builder.AppendFormat(CultureInfo.CurrentCulture, "Error on line {0} at position {1}:\n", format); 37 | // the actual error message 38 | builder.AppendLine(msg); 39 | #if MY_DEBUG 40 | builder.AppendLine($"Debug: Offending symbol type: {recognizer.Vocabulary.GetSymbolicName(offendingSymbol.Type)}"); 41 | #endif 42 | 43 | if (offendingSymbol.TokenSource != null) 44 | { 45 | // the line with the error on it 46 | string input = offendingSymbol.TokenSource.InputStream.ToString(); 47 | string[] lines = input.Split('\n'); 48 | string errorLine = lines[line - 1]; 49 | builder.AppendLine(errorLine); 50 | 51 | // adding indicator symbols pointing out where the error is on the line 52 | int start = offendingSymbol.StartIndex; 53 | int stop = offendingSymbol.StopIndex; 54 | if (start >= 0 && stop >= 0) 55 | { 56 | // the end point of the error in "line space" 57 | int end = (stop - start) + charPositionInLine + 1; 58 | for (int i = 0; i < end; i++) 59 | { 60 | // move over until we are at the point we need to be 61 | if (i >= charPositionInLine && i < end) 62 | { 63 | builder.Append("^"); 64 | } 65 | else 66 | { 67 | builder.Append(" "); 68 | } 69 | } 70 | } 71 | } 72 | 73 | 74 | throw new ParseException(builder.ToString()); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /Diana/Data.cs.in: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | 7 | namespace Diana 8 | { 9 | 10 | {% for defi in defs %} 11 | [Serializable] 12 | public partial class {{defi.name}} : ImmediateAST 13 | { 14 | 15 | int ImmediateAST.Lineno { set => lineno = value; get => lineno; } 16 | int ImmediateAST.Colno { set => colno = value; get => colno; } 17 | 18 | public void __default_resolve_local(MetaContext ctx) 19 | { 20 | {% for field in defi if field.name not in ("lineno", "colno") and NET_filter(field.type) not in ("int", "string", "float") %} 21 | {{field.name}}?.__resolve_local(ctx); 22 | {% endfor %} 23 | } 24 | 25 | public string description => "{{defi.name}}"; 26 | 27 | {% for field in defi %} 28 | public {{field.type | NET}} {{field.name}}; 29 | {% endfor %} 30 | public static {{defi.name}} make( 31 | {% for field in defi if field.name not in ("lineno", "colno") %} 32 | {{field.type | NET}} {{field.name}}, 33 | {% endfor %} 34 | int lineno, 35 | int colno 36 | ) => new {{defi.name}} { 37 | {% for field in defi %} 38 | {{field.name}} = {{field.name}}, 39 | {% endfor %} 40 | }; 41 | } 42 | {% endfor %} 43 | 44 | public partial class ByteASTLoader 45 | { 46 | 47 | private ImmediateAST Read(THint _) => ReadImmediateAST(); 48 | 49 | public ImmediateAST ReadImmediateAST() 50 | { 51 | var code = (int) ReadTag(); 52 | switch (code) 53 | { 54 | {% for defi in defs %} 55 | case {{defi.tag}}: 56 | { 57 | return new {{defi.name}} 58 | { 59 | {% for field in defi %} 60 | {% if isinstance(field.type, TArr) %} 61 | {% do ARR_TYPES.add(field.type.eltype) %} 62 | {{field.name}} = Read(THint<{{field.type | NET }}>.val), 63 | {%else %} 64 | {{field.name}} = Read(THint<{{field.type | NET }}>.val), 65 | {% endif %} 66 | {% endfor %} 67 | }; 68 | } 69 | {% endfor %} 70 | default: 71 | throw new InvalidDataException($"invalid code {code}"); 72 | } 73 | 74 | } 75 | 76 | {% for defi in defs %} 77 | 78 | private {{defi.name}} Read(THint<{{ defi.name }}> _) => Read{{defi.name}}(); 79 | 80 | public {{defi.name}} Read{{ defi.name }}() => new {{ defi.name }} 81 | { 82 | {% for field in defi %} 83 | {% if isinstance(field.type, TArr) %} 84 | {% do ARR_TYPES.add(field.type.eltype) %} 85 | {% endif %} 86 | {{field.name}} = Read(THint<{{field.type|NET}}>.val), 87 | {% endfor %} 88 | }; 89 | 90 | {% endfor %} 91 | 92 | private static readonly object _loaderSync = new object(); 93 | 94 | {% for type in ARR_TYPES %} 95 | public {{ type | NET }}[] Read(THint<{{type | NET}}[]> _) 96 | { 97 | var arr = new {{type | NET }}[ReadInt()]; 98 | for(var i = 0; i < arr.Length; i++) 99 | { 100 | arr[i] = Read(THint<{{type | NET }}>.val); 101 | } 102 | return arr; 103 | } 104 | {% endfor %} 105 | 106 | } // loader class 107 | } // aworld 108 | -------------------------------------------------------------------------------- /codegen/def.spec: -------------------------------------------------------------------------------- 1 | StoreMany( 2 | int lineno, int colno, 3 | (ImmediateAST, string)[] lhs, ImmediateAST rhs) 4 | 5 | Bin( 6 | int lineno, 7 | int colno, 8 | ImmediateAST left, 9 | string op, 10 | ImmediateAST right) 11 | 12 | 13 | Load( 14 | int lineno, 15 | int colno, 16 | string n) 17 | 18 | IfThenElse( 19 | int lineno, 20 | int colno, 21 | ImmediateAST cond, 22 | ImmediateAST then, 23 | ImmediateAST orelse) 24 | 25 | NestedIf( 26 | int lineno, 27 | int colno, 28 | (ImmediateAST, ImmediateAST)[] elifs, 29 | ImmediateAST orelse) 30 | 31 | 32 | While( 33 | int lineno, 34 | int colno, 35 | ImmediateAST cond, 36 | ImmediateAST then 37 | ) 38 | 39 | Raise( 40 | int lineno, 41 | int colno, 42 | ImmediateAST expr 43 | ) 44 | 45 | 46 | Loop( 47 | int lineno, 48 | int colno, 49 | ImmediateAST body 50 | ) 51 | 52 | Meta( 53 | int lineno, 54 | int colno, 55 | int filename_idx, 56 | ImmediateAST inner 57 | ) 58 | 59 | SetMeta( 60 | int lineno, 61 | int colno, 62 | int idx, 63 | string filename 64 | ) 65 | 66 | For( 67 | int lineno, 68 | int colno, 69 | string target, 70 | ImmediateAST iter, 71 | ImmediateAST body 72 | ) 73 | 74 | 75 | OGet( 76 | int lineno, 77 | int colno, 78 | ImmediateAST target, 79 | ImmediateAST item 80 | ) 81 | 82 | 83 | Block( 84 | int lineno, 85 | int colno, 86 | ImmediateAST[] suite 87 | ) 88 | 89 | Call( 90 | int lineno, 91 | int colno, 92 | ImmediateAST f, 93 | ImmediateAST[] args 94 | ) 95 | 96 | Function( 97 | int lineno, 98 | int colno, 99 | string name, 100 | string[] args, 101 | ImmediateAST body 102 | ) 103 | 104 | CVal( 105 | int lineno, 106 | int colno, 107 | DObj obj 108 | ) 109 | 110 | CList( 111 | int lineno, 112 | int colno, 113 | ImmediateAST[] elts 114 | ) 115 | 116 | CTuple( 117 | int lineno, 118 | int colno, 119 | ImmediateAST[] elts 120 | ) 121 | 122 | CDict( 123 | int lineno, 124 | int colno, 125 | (ImmediateAST, ImmediateAST)[] pairs 126 | ) 127 | 128 | CSet( 129 | int lineno, 130 | int colno, 131 | ImmediateAST[] elts 132 | ) 133 | 134 | Break( 135 | int lineno, 136 | int colno 137 | ) 138 | 139 | Continue( 140 | int lineno, 141 | int colno 142 | ) 143 | 144 | Return( 145 | int lineno, 146 | int colno, 147 | ImmediateAST value 148 | ) 149 | 150 | And( 151 | int lineno, 152 | int colno, 153 | ImmediateAST left, 154 | ImmediateAST right 155 | ) 156 | 157 | Or( 158 | int lineno, 159 | int colno, 160 | ImmediateAST left, 161 | ImmediateAST right 162 | ) 163 | 164 | Not( 165 | int lineno, 166 | int colno, 167 | ImmediateAST value 168 | ) 169 | 170 | Neg( 171 | int lineno, 172 | int colno, 173 | ImmediateAST value 174 | ) 175 | 176 | 177 | Inv( 178 | int lineno, 179 | int colno, 180 | ImmediateAST value 181 | ) 182 | 183 | Decl( 184 | int lineno, 185 | int colno, 186 | string[] names 187 | ) 188 | 189 | Symbol( 190 | int lineno, 191 | int colno, 192 | string name 193 | ) 194 | 195 | Pipeline( 196 | int lineno, 197 | int colno, 198 | ImmediateAST head, 199 | ImmediateAST[] tail 200 | ) 201 | 202 | Option( 203 | int lineno, 204 | int colno, 205 | string attr, 206 | ImmediateAST[] args 207 | ) 208 | 209 | Workflow( 210 | int lineno, 211 | int colno, 212 | string bindname, 213 | ImmediateAST builder, 214 | ImmediateAST[] options 215 | ) -------------------------------------------------------------------------------- /Diana.Generated/Methods.DIterable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq;using System.Collections.Generic; 3 | namespace Diana 4 | { 5 | public partial class DIterable 6 | { 7 | public string Classname => "Enum"; 8 | public static DModule module_instance {get; private set;} 9 | public static DObj bind_foreach(DObj[] _args) // bind method 10 | { 11 | var nargs = _args.Length; 12 | if (nargs != 2) 13 | throw new ArgumentException($"calling Enum.foreach; needs at least (2) arguments, got {nargs}."); 14 | var _arg0 = MK.unbox(THint>.val, _args[0]); 15 | var _arg1 = MK.unbox(THint.val, _args[1]); 16 | { 17 | _arg0.ForEach_(_arg1); 18 | return MK.None(); 19 | } 20 | throw new ArgumentException($"call Enum.foreach; needs at most (2) arguments, got {nargs}."); 21 | } 22 | public static DObj bind_map(DObj[] _args) // bind method 23 | { 24 | var nargs = _args.Length; 25 | if (nargs != 2) 26 | throw new ArgumentException($"calling Enum.map; needs at least (2) arguments, got {nargs}."); 27 | var _arg0 = MK.unbox(THint>.val, _args[0]); 28 | var _arg1 = MK.unbox(THint.val, _args[1]); 29 | { 30 | var _return = _arg0.Map(_arg1); 31 | return MK.create(_return); 32 | } 33 | throw new ArgumentException($"call Enum.map; needs at most (2) arguments, got {nargs}."); 34 | } 35 | public static DObj bind_mapi(DObj[] _args) // bind method 36 | { 37 | var nargs = _args.Length; 38 | if (nargs != 2) 39 | throw new ArgumentException($"calling Enum.mapi; needs at least (2) arguments, got {nargs}."); 40 | var _arg0 = MK.unbox(THint>.val, _args[0]); 41 | var _arg1 = MK.unbox(THint.val, _args[1]); 42 | { 43 | var _return = _arg0.MapI(_arg1); 44 | return MK.create(_return); 45 | } 46 | throw new ArgumentException($"call Enum.mapi; needs at most (2) arguments, got {nargs}."); 47 | } 48 | public static DObj bind_range(DObj[] _args) // bind method 49 | { 50 | var nargs = _args.Length; 51 | if (nargs < 1) 52 | throw new ArgumentException($"calling Enum.range; needs at least (1,2,3) arguments, got {nargs}."); 53 | var _arg0 = MK.unbox(THint.val, _args[0]); 54 | if (nargs == 1) 55 | { 56 | var _return = CollectionExts.Range(_arg0); 57 | return MK.create(_return); 58 | } 59 | var _arg1 = MK.unbox(THint.val, _args[1]); 60 | if (nargs == 2) 61 | { 62 | var _return = CollectionExts.Range(_arg0,_arg1); 63 | return MK.create(_return); 64 | } 65 | var _arg2 = MK.unbox(THint.val, _args[2]); 66 | { 67 | var _return = CollectionExts.Range(_arg0,_arg1,_arg2); 68 | return MK.create(_return); 69 | } 70 | throw new ArgumentException($"call Enum.range; needs at most (3) arguments, got {nargs}."); 71 | } 72 | public static DObj bind_rep(DObj[] _args) // bind method 73 | { 74 | var nargs = _args.Length; 75 | if (nargs != 2) 76 | throw new ArgumentException($"calling Enum.rep; needs at least (2) arguments, got {nargs}."); 77 | var _arg0 = MK.unbox(THint.val, _args[0]); 78 | var _arg1 = MK.unbox(THint.val, _args[1]); 79 | { 80 | var _return = Enumerable.Repeat(_arg0,_arg1); 81 | return MK.create(_return); 82 | } 83 | throw new ArgumentException($"call Enum.rep; needs at most (2) arguments, got {nargs}."); 84 | } 85 | static DIterable() 86 | { 87 | module_instance = new DModule("Enum"); 88 | module_instance.fields.Add("foreach", MK.FuncN("Enum.foreach", bind_foreach)); 89 | module_instance.fields.Add("map", MK.FuncN("Enum.map", bind_map)); 90 | module_instance.fields.Add("mapi", MK.FuncN("Enum.mapi", bind_mapi)); 91 | module_instance.fields.Add("range", MK.FuncN("Enum.range", bind_range)); 92 | module_instance.fields.Add("rep", MK.FuncN("Enum.rep", bind_rep)); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /codegen/binding.spec: -------------------------------------------------------------------------------- 1 | boxedtypes { 2 | DObj 3 | DList 4 | DDict 5 | DInt 6 | DString 7 | DFloat 8 | DNone 9 | DTuple 10 | DFunc 11 | } 12 | 13 | // name in script language, name in .net, .net wrap type name 14 | 15 | 16 | "using System.Collections.Generic;" 17 | Dict DDict Dictionary { 18 | void this.Remove(DObj) as remove 19 | void this.Clear() as clear 20 | void this.Count as len 21 | void this.ContainsKey(DObj) as contains 22 | bool this.TryGetValue(DObj, out DObj) as search 23 | bool CollectionExts.DifferenceDObj(Dictionary, DObj) as subtract 24 | bool CollectionExts.Union(Dictionary, IEnumerable) as union 25 | Dictionary CollectionExts.UnionDict(Dictionary, Dictionary) as union_dict 26 | bool CollectionExts.Intersect(Dictionary, IEnumerable) as intersect 27 | void CollectionExts.AddAsSet(Dictionary, DObj) as add 28 | bool this DDict.__truediv__(DObj) as quotient 29 | IEnumerable CollectionExts.ObjectPairs(Dictionary) as items 30 | void this.ForEachIndex_(DObj) as forkey 31 | void this.Merge(Dictionary) as update 32 | Dictionary CollectionExts.dictOf(IEnumerable) as of 33 | Dictionary CollectionExts.setOf(IEnumerable) as setOf 34 | Dictionary this.ShallowCopy() as copy 35 | } 36 | 37 | "using System.Collections.Generic;" 38 | Str DString String { 39 | String Join(String, IEnumerable from DObj) as join 40 | String Concat(IEnumerable from DObj) as concat 41 | bool this.EndsWith(String) as endswith 42 | bool this.StartsWith(String) as startswith 43 | int this.Length as len 44 | String this.Trim(Char[]? from String) as strip 45 | String this.TrimEnd(Char[]? from String) as rstrip 46 | String this.TrimStart(Char[]? from String) as lstrip 47 | String this.ToLowerInvariant() as lower 48 | String this.ToUpperInvariant() as upper 49 | bool this.Contains(String) as contains 50 | String String.Format(String, *Object) as format 51 | String this.Substring(Int32, Int32?) as substr 52 | String this.Insert(Int32, String) as insert 53 | String this.Remove(Int32, Int32?) as remove_at 54 | int this.IndexOf(String, Int32?, Int32?) as index 55 | DObj TypeConversion.toStr(DObj) as of 56 | } 57 | 58 | Int DInt Int64 { 59 | Int64 MaxValue as get_max 60 | Int64 MinValue as get_min 61 | DObj TypeConversion.toInt(DObj) as of 62 | } 63 | 64 | Num DFloat Single { 65 | float MaxValue as get_max 66 | float MinValue as get_min 67 | DObj TypeConversion.toFloat(DObj) as of 68 | } 69 | 70 | "using System.Linq;" 71 | "using System.Collections.Generic;" 72 | Tuple DTuple DObj[] { 73 | int this.Length as len 74 | DObj[] this IEnumerable .ToArray() as of 75 | void this.ForEachIndex_(DObj) as forkey 76 | } 77 | 78 | "using System.Linq;" 79 | "using System.Collections.Generic;" 80 | List DList List { 81 | void this.Add(DObj) as push 82 | void this.AddRange(IEnumerable) as extend 83 | void this.Insert(Int32, DObj) as insert 84 | void this.Remove(DObj) as remove 85 | DObj this.Pop() as pop 86 | DObj this.Find(Predicate) as find 87 | void this.IndexOf(DObj, Int32?) as index 88 | void this.RemoveAt(Int32) as remove_at 89 | void this.Sort() as sort 90 | DObj[] this.ToArray() as array 91 | void this.Clear() as clear 92 | List this IEnumerable .ToList() as of 93 | void this.ForEachIndex_(DObj) as forkey 94 | List this.ShallowCopy() as copy 95 | } 96 | 97 | "using System.Linq;" 98 | "using System.Collections.Generic;" 99 | Enum DIterable IEnumerable 100 | { 101 | void this.ForEach_(DObj) as foreach 102 | IEnumerable this.Map(DObj) as map 103 | IEnumerable this.MapI(DObj) as mapi 104 | IEnumerable CollectionExts.Range(Int64, Int64?, Int64?) as range 105 | IEnumerable Enumerable.Repeat(DObj, Int32) as rep 106 | } 107 | 108 | // override Equals according to "==" 109 | // override ToString according to "__str__" 110 | // 111 | -------------------------------------------------------------------------------- /Diana/JITSupport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Runtime.CompilerServices; 6 | 7 | namespace Diana 8 | { 9 | 10 | using NameSpace = Dictionary; 11 | using CPS = Func; 12 | 13 | public class Variable 14 | { 15 | public DObj obj; 16 | } 17 | public class ExecContext 18 | { 19 | public int CONT; 20 | public Variable[] localvars; 21 | public Variable[] freevars; 22 | public NameSpace ns; 23 | public Metadata co; 24 | 25 | static Variable[] emptyVariableArray = new Variable[0]; 26 | public static DObj ExecTopLevel(CPS cps, NameSpace ns, Metadata co) 27 | { 28 | return cps(new ExecContext(emptyVariableArray, emptyVariableArray, ns, co)); 29 | } 30 | 31 | public ExecContext(Variable[] localvars, Variable[] freevars, NameSpace ns, Metadata co) 32 | { 33 | this.CONT = 0; 34 | this.localvars = localvars; 35 | this.freevars = freevars; 36 | this.ns = ns; 37 | this.co = co; 38 | } 39 | 40 | [MethodImpl(MethodImplOptionsCompat.AggressiveInlining | MethodImplOptionsCompat.AggressiveOptimization)] 41 | public DObj loadGlobal(string n) 42 | { 43 | if (ns.TryGetValue(n, out var obj)) 44 | { 45 | return obj; 46 | } 47 | throw new NameError("global", n); 48 | } 49 | 50 | [MethodImpl(MethodImplOptionsCompat.AggressiveInlining | MethodImplOptionsCompat.AggressiveOptimization)] 51 | public DObj loadLocal(int i) 52 | { 53 | DObj obj; 54 | if ((obj = localvars[i].obj) != null) 55 | { 56 | return obj; 57 | } 58 | throw new NameError("local", co.localnames[i]); 59 | } 60 | 61 | [MethodImpl(MethodImplOptionsCompat.AggressiveInlining | MethodImplOptionsCompat.AggressiveOptimization)] 62 | public DObj loadFree(int i) 63 | { 64 | DObj obj; 65 | if ((obj = freevars[i].obj) != null) 66 | { 67 | return obj; 68 | } 69 | throw new NameError("free", co.freenames[i]); 70 | } 71 | } 72 | 73 | [Serializable] 74 | [ImmutableObject(true)] 75 | public class SourcePos 76 | { 77 | public int line; 78 | public int col; 79 | public string filename; 80 | public SourcePos(int l, int c, string f) 81 | { 82 | line = l; 83 | col = c; 84 | filename = f; 85 | } 86 | public void visit(MetaContext ctx) 87 | { 88 | var p = ctx.currentPos; 89 | if (p.line == line && p.col == col && p.filename == filename) 90 | return; 91 | ctx.currentPos = this; 92 | } 93 | } 94 | 95 | public static class Prime2 96 | { 97 | static List> funcs = new List>(); 98 | 99 | static Dictionary indices = new Dictionary(); 100 | 101 | public static DObj callfunc2(int i, DObj l, DObj r) 102 | { 103 | return funcs[i](l, r); 104 | } 105 | 106 | public static int getFuncIdx(string n) 107 | { 108 | return indices[n]; 109 | } 110 | 111 | public static Func getFunc(string n) 112 | { 113 | return funcs[indices[n]]; 114 | } 115 | public static int addFunc(string n, Func func) 116 | { 117 | if (indices.TryGetValue(n, out int i)) 118 | { 119 | return i; 120 | } 121 | funcs.Add(func); 122 | i = funcs.Count - 1; 123 | indices[n] = i; 124 | return i; 125 | } 126 | 127 | } 128 | 129 | [Serializable] 130 | public sealed record Metadata( 131 | int narg, 132 | int nlocal, 133 | SourcePos pos, 134 | string name, 135 | string[] localnames, 136 | string[] freenames 137 | ) : DObj 138 | { 139 | public object Native => this; 140 | public string Classname => "code"; 141 | 142 | public string __str__() => $""; 143 | 144 | public bool __eq__(DObj o) 145 | { 146 | return (o is Metadata code) && code == this; 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /Diana/ObjectSystem.Default.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | 6 | namespace Diana 7 | { 8 | public interface DObj : IEquatable 9 | { 10 | bool IEquatable.Equals(DObj other) 11 | { 12 | return __eq__(other); 13 | } 14 | public bool __bool__() => true; 15 | public object Native => this; 16 | public string Classname => this.GetType().Name; 17 | public string __str__() => Native.ToString(); 18 | public string __repr__() => __str__(); 19 | public DObj __next__() => throw unsupported_op(this, "__next__"); 20 | static Exception unsupported_op(DObj a, string op) => 21 | new TypeError($"{a.Classname} does not support '{op}'"); 22 | public DObj __add__(DObj a) 23 | { 24 | throw unsupported_op(this, "+"); 25 | } 26 | 27 | public DObj __bitand__(DObj a) 28 | { 29 | throw unsupported_op(this, "&"); 30 | } 31 | 32 | public DObj __bitor__(DObj a) 33 | { 34 | throw unsupported_op(this, "|"); 35 | } 36 | 37 | public DObj __bitxor__(DObj a) 38 | { 39 | throw unsupported_op(this, "^"); 40 | } 41 | 42 | public DObj __call__(params DObj[] objs) 43 | { 44 | throw unsupported_op(this, "__call__"); 45 | } 46 | 47 | public DObj __call0__() 48 | { 49 | return __call__(); 50 | } 51 | 52 | public DObj __call1__(DObj o) 53 | { 54 | return __call__(o); 55 | } 56 | 57 | public DObj __call2__(DObj arg1, DObj arg2) 58 | { 59 | return __call__(arg1, arg2); 60 | } 61 | 62 | public bool __contains__(DObj a) 63 | { 64 | throw unsupported_op(this, "__contains__"); 65 | } 66 | 67 | public bool __eq__(DObj o) 68 | { 69 | return Object.ReferenceEquals(o.Native, this.Native); 70 | } 71 | 72 | public DObj __floordiv__(DObj a) 73 | { 74 | throw unsupported_op(this, "//"); 75 | } 76 | 77 | public DObj __get__(DObj s) 78 | { 79 | throw unsupported_op(this, "__get__"); 80 | } 81 | 82 | public void __set__(DObj s, DObj value) 83 | { 84 | throw unsupported_op(this, "__set__"); 85 | } 86 | 87 | public DObj __inv__() 88 | { 89 | throw unsupported_op(this, "__inv__"); 90 | } 91 | 92 | public IEnumerable __iter__() 93 | { 94 | throw unsupported_op(this, "__iter__"); 95 | } 96 | 97 | public int __len__() 98 | { 99 | throw unsupported_op(this, "__len__"); 100 | } 101 | 102 | public DObj __lshift__(DObj a) 103 | { 104 | throw unsupported_op(this, "<<"); 105 | } 106 | 107 | public bool __lt__(DObj o) 108 | { 109 | throw unsupported_op(this, "<"); 110 | } 111 | 112 | public DObj __mod__(DObj a) 113 | { 114 | throw unsupported_op(this, "%"); 115 | } 116 | 117 | public DObj __mul__(DObj a) 118 | { 119 | throw unsupported_op(this, "*"); 120 | } 121 | 122 | public DObj __neg__() 123 | { 124 | throw unsupported_op(this, "__neg__"); 125 | } 126 | 127 | public DObj __pow__(DObj a) 128 | { 129 | throw unsupported_op(this, "**"); 130 | } 131 | 132 | public DObj __rshift__(DObj a) 133 | { 134 | throw unsupported_op(this, ">>"); 135 | } 136 | 137 | public DObj __sub__(DObj a) 138 | { 139 | throw unsupported_op(this, "-"); 140 | } 141 | 142 | public DObj __truediv__(DObj a) 143 | { 144 | throw unsupported_op(this, "/"); 145 | } 146 | } 147 | 148 | public class DModule : DObj 149 | { 150 | 151 | public Dictionary fields; 152 | public string name; 153 | public string Classname => "module"; 154 | 155 | public DModule(string name) 156 | { 157 | fields = new Dictionary(); 158 | this.name = name; 159 | } 160 | 161 | public string __str__() => name; 162 | 163 | public DObj __getstr__(string field) 164 | { 165 | if(fields.TryGetValue(field, out var obj)) 166 | { 167 | return obj; 168 | } 169 | throw new AttributeError($"module {name} has no attribute {field}."); 170 | } 171 | public DObj __get__(DObj s) 172 | { 173 | var field = (s as DString)?.value; 174 | if (field == null) 175 | throw new TypeError($"a module field should be string."); 176 | return __getstr__(field); 177 | } 178 | } 179 | 180 | public partial class DIterable : DObj 181 | { 182 | public string __str__() => $"<{module_instance.name}>"; 183 | public Dictionary fields; 184 | 185 | public IEnumerable iter; 186 | public DIterable(IEnumerable iter) 187 | { 188 | this.iter = iter; 189 | } 190 | public IEnumerable __iter__() => iter; 191 | } 192 | } -------------------------------------------------------------------------------- /Diana.Frontend/OperatorResolver.cs: -------------------------------------------------------------------------------- 1 | /* 2 | C# implementation of "operator bubbling". 3 | The original works of this algorithm is made by Taine Zhao(twshere@outlook.com) and this file is licensed under MPL-2.0. 4 | */ 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | 10 | namespace Diana.Frontend 11 | { 12 | 13 | public class Operator 14 | { 15 | public string opname; 16 | public Op op; 17 | public Operator(string opname, Op op) 18 | { 19 | this.opname = opname; 20 | this.op = op; 21 | } 22 | } 23 | public class Doubly 24 | where Exp : class 25 | { 26 | public Doubly l; 27 | public object mid; 28 | public Operator op => mid as Operator; 29 | public Exp value { get => mid as Exp; set => mid = value; } 30 | public Doubly r; 31 | 32 | public Doubly(Doubly l, object mid, Doubly r) 33 | { 34 | this.l = l; 35 | this.mid = mid; 36 | this.r = r; 37 | } 38 | 39 | } 40 | 41 | 42 | public class OperatorResolver 43 | where Exp : class 44 | { 45 | 46 | public static Dictionary StandardPrecedences = new Dictionary 47 | { 48 | {"==", 1}, 49 | {"!=", 1}, 50 | {"<", 2}, 51 | {">", 2}, 52 | {"<=", 2}, 53 | {">=", 2}, 54 | {"notin", 2}, 55 | {"in", 2}, 56 | {"|", 3}, 57 | {"^", 4}, 58 | {"&", 5}, 59 | {">>", 6}, 60 | {"<<", 6}, 61 | {"+", 7}, 62 | {"-", 7}, 63 | {"*", 8}, 64 | {"/", 8}, 65 | {"//", 8}, 66 | {"%", 8}, 67 | {"**", 9} 68 | }; 69 | public static Dictionary StandardAssociativities = new Dictionary { { "**", true } }; 70 | 71 | public Func opcons; 72 | public Dictionary associativities; 73 | public Dictionary precedences; 74 | 75 | public OperatorResolver(Func opcons, Dictionary associativities = null, Dictionary precedences = null) 76 | { 77 | this.opcons = opcons; 78 | this.associativities = associativities ?? StandardAssociativities; 79 | this.precedences = precedences ?? StandardPrecedences; 80 | } 81 | 82 | public Exp binopReduce(List seq) 83 | { 84 | var start = new Doubly(null, null, null); 85 | 86 | var last = start; 87 | var ops = new List>(); 88 | 89 | foreach (var each in seq) 90 | { 91 | Doubly cur; 92 | switch (each) 93 | { 94 | case Exp exp: 95 | cur = new Doubly(last, each, null); 96 | break; 97 | 98 | case Operator op: 99 | cur = new Doubly(last, each, null); 100 | ops.Add(cur); 101 | break; 102 | default: 103 | throw new ArgumentException("input sequence should contains specified operator and expression only."); 104 | 105 | } 106 | last.r = cur; 107 | last = cur; 108 | } 109 | 110 | var final = new Doubly(last, null, null); 111 | 112 | last.r = final; 113 | var op_chunks = new Dictionary< 114 | (int precedence, bool assoc), List>>(); 115 | 116 | foreach (var op in ops) 117 | { 118 | var opname = op.op.opname; 119 | var key = (precedences[opname], associativities.TryGetValue(opname, out bool assoc)? assoc : false); 120 | if (op_chunks.TryGetValue(key, out var group)) 121 | { 122 | group.Add(op); 123 | } 124 | else 125 | { 126 | group = new List>{ 127 | op 128 | }; 129 | op_chunks[key] = group; 130 | } 131 | } 132 | var op_chunks2 = op_chunks.Select(x => (x.Key, x.Value)).ToList(); 133 | 134 | op_chunks2.Sort( 135 | (a, b) => b.Key.precedence.CompareTo(a.Key.precedence) 136 | ); 137 | ops = new List>(); 138 | foreach (((var _, var is_right_assoc), var chunk) in op_chunks2) 139 | { 140 | if (is_right_assoc) 141 | { 142 | ops.AddRange(chunk.Reverse>()); 143 | } 144 | else 145 | { 146 | ops.AddRange(chunk); 147 | } 148 | } 149 | foreach (var op in ops) 150 | { 151 | var op_v = op.op; 152 | op.value = opcons(op_v.op, op.l.value, op.r.value); 153 | op.l = op.l.l; 154 | op.r = op.r.r; 155 | op.l.r = op; 156 | op.r.l = op; 157 | } 158 | return final.l.value; 159 | } 160 | } 161 | } -------------------------------------------------------------------------------- /test/exhaustive-test.diana: -------------------------------------------------------------------------------- 1 | print = log 2 | 3 | print("================================================") 4 | 5 | True = 1 6 | False = 0 7 | 8 | log(2, 3) 9 | fun assert_and_print(test, msg) 10 | a = assert(test, msg) 11 | assert(a == None) 12 | print("passed: ", msg) 13 | end 14 | 15 | x = 2 16 | 17 | fun f(x) 18 | var x, y 19 | x = 3 20 | y = 2 21 | assert_and_print(x == 3, "local assign") 22 | log(y) 23 | end 24 | 25 | assert_and_print(x == 2, "global not polluted") 26 | 27 | f(2) 28 | 29 | fun f3(x, y, z) 30 | 31 | end 32 | 33 | f3(1, 2, 3) 34 | 35 | fun test_assign(x, y, z) 36 | x = y = z 37 | a = x 38 | assert_and_print((x == a and y == a and z == a), "multi assign") 39 | end 40 | 41 | test_assign(1, 2, 3) 42 | 43 | 44 | 45 | fun test_loop_break_and_continue() 46 | x = 0 47 | loop 48 | if x < 100 then 49 | x = x + 1 50 | continue 51 | end 52 | 53 | break 54 | end 55 | 56 | assert_and_print(x == 100, "loop break and continue") 57 | end 58 | 59 | test_loop_break_and_continue() 60 | 61 | 62 | fun test_loop_break() 63 | var x 64 | x = 0 65 | loop 66 | if x < 100 then 67 | x = x + 1 68 | else 69 | 70 | break 71 | end 72 | end 73 | 74 | assert_and_print(x == 100, "loop break") 75 | end 76 | 77 | fun test_foreach() 78 | var sum, xs, k 79 | xs = [1, 2, 3, 4, 5] 80 | sum = 0 81 | for _ in xs do 82 | sum = sum + 1 83 | end 84 | assert_and_print(sum == 5, "foreach without lhs") 85 | sum = 0 86 | for x in xs do 87 | 88 | k = x 89 | 90 | 91 | sum = sum + k 92 | end 93 | assert_and_print(sum == 15, "foreach with lhs") 94 | end 95 | 96 | 97 | test_foreach() 98 | 99 | 100 | fun test_if() 101 | var x 102 | if True then 103 | assert_and_print(True, "no else") 104 | end 105 | 106 | if False then 107 | x = 555 108 | else 109 | x = 333 110 | end 111 | assert_and_print(x != 555, "no else and false") 112 | 113 | if True then 114 | else 115 | x = 781123 116 | end 117 | 118 | assert_and_print(x != 781123, "no then and true") 119 | 120 | if False then 121 | 122 | else 123 | x = 781123 124 | end 125 | 126 | assert_and_print(x == 781123, "no then and false") 127 | 128 | end 129 | 130 | test_if() 131 | 132 | BAD = False 133 | fun test_return(x) 134 | var x, BAD 135 | if x == 1 then 136 | return "return in if" 137 | BAD = True 138 | end 139 | 140 | if x == 2 then 141 | loop 142 | return "return in loop" 143 | BAD = True 144 | end 145 | end 146 | 147 | if x == 3 then 148 | for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] do 149 | if x > 3 then 150 | return "return in for" 151 | end 152 | end 153 | BAD = True 154 | end 155 | 156 | 157 | if x == 4 then 158 | for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] do 159 | x = x + 1 160 | loop 161 | 162 | x = x + 1 163 | break 164 | end 165 | assert_and_print(x == 3, "just break") 166 | 167 | loop 168 | 169 | loop 170 | BAD = True 171 | break 172 | end 173 | 174 | loop 175 | BAD = False 176 | return "nested loop return" 177 | 178 | end 179 | end 180 | end 181 | BAD = True 182 | end 183 | 184 | BAD = True 185 | return "failed" 186 | end 187 | 188 | msg = test_return(1) 189 | assert_and_print(BAD != True, msg) 190 | 191 | msg = test_return(2) 192 | assert_and_print(BAD != True, msg) 193 | 194 | msg = test_return(3) 195 | assert_and_print(BAD != True, msg) 196 | 197 | 198 | msg = test_return(4) 199 | assert_and_print(BAD != True, msg) 200 | 201 | 202 | fun test_shortcuts() 203 | var x 204 | True or assert_and_print(False, "failed at (True or _)") 205 | 206 | False or assert_and_print(True, "succeeded at (False or _)") 207 | 208 | x = 1 209 | 210 | False or assert(x == 1) 211 | 212 | True and assert_and_print(True, "succeeded at (True and _)") 213 | 214 | False and assert_and_print(False, "failed at (False and _)") 215 | 216 | (True and True and print(2)) or print("(print(2) or _)") 217 | end 218 | 219 | 220 | test_shortcuts() 221 | 222 | fun bool(x) 223 | if x then 224 | return True 225 | else return False 226 | end 227 | end 228 | 229 | log("not 1:" + (not 1)) 230 | 231 | fun test_not() 232 | assert_and_print(not 1 == False, "not 1 == False") 233 | assert_and_print(bool(10) == True, "not 10 == False") 234 | end 235 | 236 | test_not() 237 | 238 | print({}, {1: 2}, {1: 2, 3: 4}) 239 | print((1, )) 240 | 241 | print(0b01 << 33) 242 | 243 | 244 | 245 | x = 2 246 | 247 | x += 3 248 | 249 | assert_and_print(x == 5, "assign global var") 250 | 251 | x = [2] 252 | 253 | x.[0] += 3 254 | 255 | assert_and_print(x.[0] == 5, "assign global list") 256 | 257 | x = None 258 | 259 | fun test_local_assign() 260 | var x 261 | x = 2 262 | 263 | x += 3 264 | 265 | assert_and_print(x == 5, "assign local var") 266 | 267 | x = [2] 268 | 269 | x.[0] += 3 270 | 271 | assert_and_print(x.[0] == 5, "assign local list") 272 | end 273 | 274 | test_local_assign() 275 | 276 | 277 | 278 | 279 | fun test_closure(x, z, k) 280 | var u 281 | u = 8 282 | fun (y) 283 | (x + y) * k * u + z 284 | end 285 | end 286 | 287 | assert_and_print(test_closure(1, 2, 3)(4) == 122, "test closure capture") 288 | 289 | a = [1, 2, 3] 290 | b = List.copy(a) 291 | 292 | b.[0] = 5 293 | assert_and_print(a == [1, 2, 3], "test shallow copy 1") 294 | assert_and_print(b == [5, 2, 3], "test shallow copy 2") 295 | 296 | 297 | a = {1: 1, 2: 2, 3: 3} 298 | b = Dict.copy(a) 299 | 300 | b.[1] = 5 301 | assert_and_print(a == {1: 1, 2: 2, 3: 3}, "test shallow copy 3") 302 | assert_and_print(b == {1: 5, 2: 2, 3: 3}, "test shallow copy 4") -------------------------------------------------------------------------------- /docs-CN.md: -------------------------------------------------------------------------------- 1 | 2 | ## 语法Cheat Sheet 3 | 4 | ```ruby 5 | # 这是一个注释 6 | k = x[1] = 3 # 连续赋值 7 | 8 | 9 | # 变量声明;不声明则是全局变量 10 | var x 11 | 12 | 13 | x = 0 14 | # 循环 15 | loop 16 | # if .. then ... end 17 | if x > 100 then 18 | break 19 | end 20 | x += 1 21 | end 22 | 23 | # 以上循环等价于 24 | x = 0 25 | while x <= 100 do 26 | x += 1 27 | end 28 | 29 | for i in Enum.range(20) do 30 | log(i) # 当然,你可以在循环中使用break和continue 31 | end 32 | # 0 33 | # ... 34 | # 19 35 | 36 | x = [1, 2, 3] # 列表 37 | 38 | x[0] # 1 39 | x[1] = 3 # x == [1, 3, 3] 40 | 41 | x = (1, ) # 元组 42 | x > (0, 1) # 返回1 43 | x > (1, 1) # 返回0 44 | 45 | x = {} # 集合,同时也是值为None的字典 46 | x[1] = None 47 | log(x) # {1} 48 | 49 | x[2] = 10; log(x) # {1, 2:10} 50 | 51 | x.attr = 20 # 等价与x["attr"] = 20 52 | log(x) # {1, 2:10, "attr": 20} 53 | 54 | z = if 1 then 0 else 1 end # if 是表达式 55 | 56 | # 多条件 57 | if cond1 then 58 | 1 59 | elif cond2 then 60 | 2 61 | elif cond3 then 62 | 3 63 | else 64 | 4 65 | end 66 | 67 | 68 | # 函数 69 | fun add(x, y) 70 | x + y # 不需要显式return 71 | end 72 | 73 | # 函数是值。函数是表达式。函数可以匿名。 74 | add = fun (x, y) 75 | x + y # 不需要显式return 76 | end 77 | 78 | # 如果函数体是一个简单的表达式 79 | mul10 = x -> x * 10 80 | ``` 81 | 82 | ## 基础类型 83 | 84 | 在C#中, DianaScript的所有对象都实现interface `DObj`。 85 | 86 | 你可以使用 `DObj.Native` 来获取它们的.NET表示形式。 87 | 88 | | 类型 | .NET 表示 | 字面量例子 | 89 | | --- | --- | --- | 90 | | Int | int64(System.Int64) | `1, 0xef, 0b01, 0o33` | 91 | | Num | float32(System.Single) | `1.0` | 92 | | Str | string(unicode-16 字符串) | `"ava"`, `"bela\\"la"` | 93 | | Dict | Dictionary\ | `{1: 2, "3": 4}`, `{1, 2, 3}`(字典也是集合) | 94 | | List | List\ | `[1, 2, if 1 then 2 else 3 end]` | 95 | | Tuple | DObj[] (在Diana中不可变) | `(1, ), (1, 2), (,), ()` | 96 | | Enum | IEnumerable\ | `List.map([1, 2], x -> x + 10)` | 97 | | None | 一个空结构体 `DNone` | `None` | 98 | | Func | 函数 | `x -> x, fun myfunc(x) return x end` | 99 | 100 | 101 | ## 运算符 102 | 103 | | 运算符 | 描述 | 支持的类型 | 104 | |--|--| --| 105 | |+| addition | `Int, Num, List(拼接语义,后同), Tuple` | 106 | |-| subtraction | `Int, Num, Dict(集合的差)` | 107 | |*| multiplication | `Int, Num, Str(重复字符串)` | 108 | |**| power | `Int, Num` | 109 | |/|float division | `Int, Num, Dict(商集)` | 110 | |//|floor division(get integer) | `Int, Num` | 111 | |%| modulo(not remainder) | `Int, Num` | 112 | |^| bitwise xor | `Int, Num` | 113 | |&| bitwise and/intersect | `Int, Num, Dict(集合交)` | 114 | |\|| bitwise or/union | `Int, Num, Dict(集合并)` | 115 | |!=| non-equality | All | 116 | |==| equality | All | 117 | |>, <, >=, <=| inequality | `Int, Num, Tuple` | 118 | | ~ | 字节逆 | `Int` | MAX | 119 | | - | 取负 | `Int, Num` | MAX | 120 | | not | 取否定 | any | MAX | 121 | | << | 左移字节 | `Int`(高位字节溢出会循环) | 122 | | >> | 零填充右移字节 | `Int`(低位字节被舍弃) | 123 | | in/not in | 检查存在性 | 检查键/元素是否存在于 `Dict/List/Set/Tuple/String` | 124 | 125 | ## Modules and Methods 126 | 127 | ### `Int` 128 | 129 | - `Int.get_max()`: int64 最大值 130 | - `Int.get_min()`: int64 最小值(包括负数) 131 | - `Int.of`: 转为 `Int`, 从 `Str`, `Int` 或 `Num` 132 | 133 | 134 | ### `Num` 135 | 136 | - `Num.get_max`: float32 最大值 137 | - `Num.get_min`: float32 最小值(包括负数) 138 | - `Num.of`: 转为 `Num`, 从 `Str`, `Int` 或 `Num` 139 | 140 | ### `Str` 141 | 142 | 每个Str都是一个Enum; 143 | 144 | 省略返回类型时,默认返回当前模块代表的类型,即`Str`. 145 | 146 | - `Str.of`: 把任意对象转为 `Str` 147 | - `Str.join(Str, Enum)` 148 | - `Str.concat(Enum)` 149 | - `Str.endswith(Str, Str)` 150 | - `Str.startswith(Str, Str)` 151 | - `Str.len(Str): Int` 152 | - `Str.strip(Str, Str?)` 153 | 154 | `Systen.String.Trim`的Diana包装; 当不给出第二个参数时, 去掉字符串左右的空白符. 155 | 156 | - `Str.lstrip(Str, Str?)` 157 | 158 | `Systen.String.TrimStart`的Diana包装; 当不给出第二个参数时, 去掉字符串左端的空白符. 159 | 160 | - `Str.rstrip(Str, Str?)` 161 | wrap of `Systen.String.TrimEnd`; 当不给出第二个参数时, 去掉字符串右端的空白符. 162 | 163 | - `Str.lower(Str)`, `Str.upper(Str)` 164 | wrap of `Systen.String.ToLowerInvariant/ToUpperInvariant`;将其中的英文字母全部转为小/大写 165 | 166 | - `Str.contains(String): Int` : 如果不包括,返回 0, 否则返回 1 167 | 168 | - `Str.format(Str, any1, any2, ...)`: 等价于.NET的 `System.String.Format`. 169 | 170 | - `Str.substr(Str, Int, Int?)` 171 | 172 | wrap of `Systen.String.Substring`; **第三个参数是子字符串的长度** 173 | 174 | 175 | - `Str.insert(Str, Int, Str)` 176 | 177 | wrap of `Systen.String.Insert` 178 | 179 | - `Str.remove_at(Str, Int, Str)` 180 | 181 | wrap of `Systen.String.Remove` 182 | 183 | - `Str.index(Str, Str, Int?, Int?)` 184 | 185 | wrap of `Systen.String.IndexOf` 186 | 187 | 188 | ## Tuple 189 | 190 | 每个Tuple都是一个Enum 191 | 192 | - `Tuple.of(Enum): Tuple`: 把`Enum`转为`Tuple` 193 | - `Tuple.len(Tuple): Int` 194 | 195 | - `Tuple.forkey(Tuple, function): None` 196 | 197 | ```elixir 198 | xs = (2, 4, 6) 199 | Tuple.forkey(log) 200 | # 0 201 | # 1 202 | # 2 203 | 204 | # you might use 'Enum.foreach(xs, log)' for this 205 | Tuple.forkey(i -> log(xs[i])) 206 | # 2 207 | # 4 208 | # 5 209 | ``` 210 | 211 | ## List 212 | 213 | - `List.of(Enum): Tuple`: 把`Enum`转为`List` 214 | - `List.push(List, any)` 215 | - `List.pop(List): any` 216 | - `List.extend(List, Enum)` 217 | - `List.clear(List)` 218 | - `List.find(List, function)` 219 | 220 | ```elixir 221 | List.find([1, 6, 3], x -> x % 2 == 0) 222 | # 6 223 | 224 | List.find([1, 6, 3], x -> x > 20) 225 | # None 226 | ``` 227 | - `List.index(List, any, Int?)` 228 | 229 | wrap of `System.Collections.Generic.List.IndexOf` 230 | 231 | - `List.remove_at(List, Int)` 232 | 233 | wrap of `System.Collections.Generic.List.RemoveAt` 234 | 235 | - `List.forkey(List, function)` 236 | 237 | ```julia 238 | var lst 239 | lst = [1, 2, 3] 240 | List.forkey(lst, i -> func(lst[i])) # == 'Enum.foreach(lst, func)' 241 | ``` 242 | 243 | - item index operator: 244 | 245 | ```lua 246 | x = [1, 2, 3] 247 | x[1] 248 | x[1] = 2 249 | ``` 250 | 251 | - `in`, `not in`: `elt in lst == not (elt not in lst)` 252 | 253 | ## Dict 254 | 255 | `Dict` 也是 `Set`; 一个 `Set` 是一个键对的值为`None`的`Dict`。 256 | 257 | - `Dict.of(Enum): Dict`: 从一个包含2个元素的元组(Tuple)转为字典(Dict) 258 | - `Dict.setOf(Enum): Dict`: 从Enum转为Set 259 | - `Dict.remove(Dict, any key): None` 260 | - `Dict.clear(Dict)` 261 | - `Dict.len(Dict): int` 262 | - `Dict.len(Dict): int` 263 | - `Dict.contains(Dict d, any key): Int`: 等价于 `key in d` 或 `not (key not in d)` 264 | - `Dict.search(Dict, any key, List ref): Int` 265 | 266 | wrap of `System.Collections.Generic.Dictionary.TryGetValue`. 267 | 268 | 找到`key`则返回1,并将`ref`的第一个元素设置为找到的值; 否则返回0 269 | 270 | ```python 271 | found_ref = [None] 272 | Dict.search({"key": "value"} 1, found_ref) # 1 273 | found_ref # ["value"] 274 | ``` 275 | 276 | - `Dict.subtract(Dict, Enum)`: 和集合的`-`运算符一致; set difference 277 | 278 | ```python 279 | x = {1, 2, 3} 280 | Dict.subtract(x, [1, 2]) # {3} 281 | ``` 282 | - `Dict.union(Dict, Enum)`: 和集合的`|`运算符一致;; set union 283 | 284 | - `Dict.intersect(Dict, Enum)`: 和集合的`&`运算符一致;; set intersect 285 | 286 | - `Dict.update(Dict, Dict)`: 用第二个字典的键对更新第一个字段 287 | - `Dict.forkey(Dict, function)` 288 | 289 | 290 | ## Enum 291 | 292 | - `Enum.foreach(Enum, func): None` 293 | 294 | - `Enum.map(Enum, func): Enum` 295 | 296 | - `Enum.mapi(Enum, func): Enum` : 这个函数参数接受两个参数;其中第一个参数是整数,表示当前元素在序列中的序号. 297 | 298 | - `Enum.range(Int start, Int end, Int sep)` 299 | - `Enum.range(Int n)` 300 | 301 | 302 | -------------------------------------------------------------------------------- /Diana/MK.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.CompilerServices; 5 | using int_t = System.Int64; 6 | 7 | namespace Diana 8 | { 9 | public struct THint 10 | { 11 | public static THint val; 12 | } 13 | 14 | 15 | public static class MK 16 | { 17 | public static DObj unbox(THint _, DObj o) => o; 18 | public static IEnumerable unbox(THint> _, DObj o) => o.__iter__(); 19 | public static Ref unbox(THint _, DObj o) => (Ref)o; 20 | public static Dictionary unbox(THint> _, DObj o) => ((DDict)o).dict; 21 | public static DObj[] unbox(THint _, DObj o) => ((DTuple)o).elts; 22 | public static List unbox(THint> _, DObj o) => ((DList)o).elts; 23 | 24 | public static Predicate unbox(THint> _, DObj o) 25 | { 26 | return (arg) => o.__call__(arg).__bool__(); 27 | } 28 | public static A unbox(THint _, DObj a) where A : DObj => (A)a; 29 | public static int unbox(THint _, DObj a) => (int)(DInt)a; 30 | public static long unbox(THint _, DObj a) => (long)(DInt)a; 31 | public static ulong unbox(THint _, DObj a) => (ulong)(DInt)a; 32 | public static uint unbox(THint _, DObj a) => (uint)(DInt)a; 33 | public static byte unbox(THint _, DObj a) => (byte)(DInt)a; 34 | 35 | public static float unbox(THint _, DObj a) => (float)(DFloat)a; 36 | public static string unbox(THint _, DObj a) => (string)(DString)a; 37 | 38 | public static A unbox(THint _, B o) where B : A => o; 39 | 40 | public static DObj cast(THint _, DObj o) => o; 41 | public static B cast(THint _, A o) where A : B => o; 42 | public static A cast(THint _, B o) where A : B => (A)o; 43 | 44 | public static DObj cast(THint _, string s) => MK.String(s); 45 | public static Char[] cast(THint _, String s) => s.ToCharArray(); 46 | public static String cast(THint _, Char[] s) => new String(s); 47 | public static String cast(THint _, Char s) => new String(new[] { s }); 48 | public static String cast(THint _, DObj a) => a.__str__(); 49 | public static String[] cast(THint _, DObj a) => 50 | a.__iter__().Select(x => x.__str__()).ToArray(); 51 | 52 | public static IEnumerable cast(THint> _, DObj a) => 53 | a.__iter__().Select(x => x.__str__()); 54 | 55 | 56 | public static float cast(THint _, int s) => s; 57 | public static int cast(THint _, float s) => (int)s; 58 | public static float cast(THint _, long s) => s; 59 | public static long cast(THint _, float s) => (int)s; 60 | 61 | public static uint cast(THint _, int_t s) => unchecked((uint)s); 62 | public static ulong cast(THint _, int_t s) => unchecked((ulong)s); 63 | 64 | public static IEnumerable cast(THint> _, DObj s) => s.__iter__(); 65 | public static bool cast(THint _, DObj s) => s.__bool__(); 66 | public static A cast(THint _, A s) => s; 67 | 68 | 69 | public static DObj create(string s) => 70 | MK.String(s == null ? "" : s); 71 | public static DObj create(DObj s) => 72 | s == null ? DNone.unique : s; 73 | public static DObj create(int s) => Int(s); 74 | public static DObj create(bool s) => Int(s); 75 | public static DObj create(long s) => Int(s); 76 | public static DObj create(ulong s) => Int(s); 77 | public static DObj create(uint s) => Int(s); 78 | 79 | const int CACHE_BOUND = 32; 80 | static DInt[] cache_integers = new DInt[CACHE_BOUND * 2]; 81 | 82 | static MK() 83 | { 84 | for (var i = -CACHE_BOUND; i < CACHE_BOUND; i++) 85 | { 86 | cache_integers[i + CACHE_BOUND] = new DInt { value = i }; 87 | } 88 | Zero = CacheOrNewInt(0); 89 | One = CacheOrNewInt(1); 90 | } 91 | 92 | [MethodImpl(MethodImplOptionsCompat.AggressiveInlining | MethodImplOptionsCompat.AggressiveOptimization)] 93 | static DInt CacheOrNewInt(long value) 94 | { 95 | if (value >= -CACHE_BOUND && value < CACHE_BOUND) 96 | { 97 | return cache_integers[value + CACHE_BOUND]; 98 | } 99 | return new DInt { value = value }; 100 | } 101 | 102 | public static DInt Zero; 103 | public static DInt One; 104 | public static DInt Int(int i) => CacheOrNewInt(i); 105 | public static DInt Int(bool i) => i ? One : Zero; 106 | public static DInt Int(long i) => CacheOrNewInt(i); 107 | public static DInt Int(ulong i) => CacheOrNewInt((int_t)i); 108 | public static DInt Int(uint i) => CacheOrNewInt((int_t)i); 109 | 110 | 111 | public static DObj create(float s) => Float(s); 112 | public static DFloat Float(float f) => new DFloat { value = f }; 113 | 114 | 115 | public static DString String(string f) => new DString { value = f }; 116 | 117 | 118 | 119 | public static DObj create() => None(); 120 | public static DNone None() => DNone.unique as DNone; 121 | 122 | public static DObj create(IEnumerable iter) => new DIterable(iter); 123 | 124 | 125 | 126 | public static DObj create(List d) => List(d); 127 | public static DObj List(List dObjs) 128 | { 129 | return new DList { elts = dObjs }; 130 | } 131 | 132 | 133 | 134 | public static DObj create(DObj[] d) => Tuple(d); 135 | public static DObj Tuple(DObj[] dObjs) 136 | { 137 | return new DTuple { elts = dObjs }; 138 | } 139 | 140 | public static DObj create(Dictionary d) => Dict(d); 141 | 142 | public static DObj Dict(Dictionary dObjs) 143 | { 144 | return new DDict { dict = dObjs }; 145 | } 146 | 147 | public static DFunc0 Func0(string name, Func f) 148 | { 149 | 150 | return new DFunc0 { func = f, name = name }; 151 | } 152 | 153 | public static DFunc1 Func1(string name, Func f) 154 | { 155 | return new DFunc1 { func = f, name = name }; 156 | } 157 | 158 | public static DFunc Func2(string name, Func f) 159 | { 160 | DObj call(DObj[] args) 161 | { 162 | if (args.Length < 2) 163 | throw new ArgumentException($"{name} requires more than 2 arguments."); 164 | return f(args[0], args[1]); 165 | } 166 | 167 | return new DFunc { func = call, name = name }; 168 | } 169 | 170 | public static DFunc FuncN(string name, Func f) 171 | { 172 | return new DFunc { func = f, name = name }; 173 | } 174 | 175 | public static DTuple tuple(params DObj[] args) 176 | { 177 | return new DTuple { elts = args }; 178 | } 179 | 180 | public static DNative wrap(object arg) 181 | { 182 | return new DNative { value = arg }; 183 | } 184 | } 185 | } -------------------------------------------------------------------------------- /sigs-for-builtin-modules.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "module": "Int", 4 | "doc": "64-bit integer/C# long", 5 | "methods": [ 6 | { 7 | "name": "get_max", 8 | "type": "get_max : () -> Int", 9 | "doc": "get max value of int64" 10 | }, 11 | { 12 | "name": "get_min", 13 | "type": "get_min : () -> Int", 14 | "doc": "get min value of int64" 15 | }, 16 | { 17 | "name": "of", 18 | "type": "of : (Int | Str | Num) -> Int", 19 | "doc": "convert to `Int`, from `Str`, `Int` or `Num`" 20 | } 21 | ] 22 | }, 23 | { 24 | "module": "Num", 25 | "doc": "32-bit float/C# float", 26 | "methods": [ 27 | { 28 | "name": "get_max", 29 | "type": "get_max : () -> Num", 30 | "doc": "get max value of float32" 31 | }, 32 | { 33 | "name": "get_min", 34 | "type": "get_min : () -> Num", 35 | "doc": "get min value of float32" 36 | }, 37 | { 38 | "name": "of", 39 | "type": "of : (Int | Str | Num) -> Num", 40 | "doc": "convert to `Num`, from `Str`, `Int` or `Num`" 41 | } 42 | ] 43 | }, 44 | { 45 | "module": "Str", 46 | "doc": "Unicode-16 strings", 47 | "methods": [ 48 | { 49 | "name": "of", 50 | "type": "of : any -> Str", 51 | "doc": "convert any to `Str`" 52 | }, 53 | { 54 | "name": "join", 55 | "type": "join : (Str, Enum) -> Str" 56 | }, 57 | { 58 | "name": "concat", 59 | "type": "concat : (Enum) -> Str" 60 | }, 61 | { 62 | "name": "endswith", 63 | "type": "endswith : (Str, Str) -> Str" 64 | }, 65 | { 66 | "name": "startswith", 67 | "type": "startswith : (Str, Str) -> Str" 68 | }, 69 | { 70 | "name": "len", 71 | "type": "len : (Str) -> Int" 72 | }, 73 | { 74 | "name": "strip", 75 | "type": "strip : (Str, Str) -> Str" 76 | }, 77 | { 78 | "name": "lstrip", 79 | "type": "lstrip : (Str, Str) -> Str" 80 | }, 81 | { 82 | "name": "rstrip", 83 | "type": "rstrip : (Str, Str) -> Str" 84 | }, 85 | { 86 | "name": "lower", 87 | "type": "lower : (Str) -> Str" 88 | }, 89 | { 90 | "name": "upper", 91 | "type": "upper : (Str) -> Str" 92 | }, 93 | { 94 | "name": "contains", 95 | "type": "contains : (Str) -> Int" 96 | }, 97 | { 98 | "name": "format", 99 | "type": "format : (Str, any...) -> Str" 100 | }, 101 | { 102 | "name": "substr", 103 | "type": "substr : (Str, Int start, Int len) -> Str" 104 | }, 105 | { 106 | "name": "insert", 107 | "type": "insert : (Str, Int pos, Str) -> Str" 108 | }, 109 | { 110 | "name": "remove_at", 111 | "type": "remove_at : (Str, Int pos, Str) -> Str" 112 | }, 113 | { 114 | "name": "index", 115 | "type": "index : (Str, Str, Int? startindex=0, Int? count=1) -> Str" 116 | }, 117 | { 118 | "name": "forkey", 119 | "type": "forkey : (Str, (Int key) -> any)) -> None" 120 | } 121 | ] 122 | }, 123 | { 124 | "module": "Tuple", 125 | "doc": "array of Diana objects; immutable", 126 | "methods": [ 127 | { 128 | "name": "of", 129 | "type": "of : (Enum) -> Tuple", 130 | "doc": "convert any enumerable of diana objects to a tuple" 131 | }, 132 | { 133 | "name": "len", 134 | "type": "len : (Tuple) -> Int" 135 | }, 136 | { 137 | "name": "forkey", 138 | "type": "forkey : (Tuple, (Int key) -> any)) -> None" 139 | } 140 | ] 141 | }, 142 | { 143 | "module": "List", 144 | "doc": "System.Collections.Generic", 145 | "methods": [ 146 | { 147 | "name": "of", 148 | "type": "of : (Enum) -> List" 149 | }, 150 | { 151 | "name": "push", 152 | "type": "push : (List, any) -> None" 153 | }, 154 | { 155 | "name": "pop", 156 | "type": "pop : (List) -> any" 157 | }, 158 | { 159 | "name": "extend", 160 | "type": "extend : (List, Enum) -> None" 161 | }, 162 | { 163 | "name": "clear", 164 | "type": "clear : (List) -> None" 165 | }, 166 | { 167 | "name": "find", 168 | "type": "clear : (List, (any) -> any) -> None", 169 | "doc": "List.find([1, 6, 3], x -> x % 2 == 0)\n# 6\nList.find([1, 6, 3], x -> x > 20)\n# None" 170 | }, 171 | { 172 | "name": "index", 173 | "type": "index : (List, any, Int?) -> Int" 174 | }, 175 | { 176 | "name": "remove_at", 177 | "type": "remove_at : (List, Int) -> None" 178 | }, 179 | { 180 | "name": "forkey", 181 | "type": "forkey : (List, (Int) => any) -> None" 182 | }, 183 | { 184 | "name": "copy" 185 | } 186 | ] 187 | }, 188 | { 189 | "module": "Dict", 190 | "doc": "module for Dictionaries and sets; when converting `Dict` to an enumerable, you get `Dict` keys.", 191 | "methods": [ 192 | { 193 | "name": "of", 194 | "type": "of : (Enum<(any, any)>) -> Dict" 195 | }, 196 | { 197 | "name": "setOf", 198 | "type": "setOf : Enum<(any)> -> Dict" 199 | }, 200 | { 201 | "name": "remove", 202 | "type": "remove : (Dict, key) -> None" 203 | }, 204 | { 205 | "name": "contains" 206 | }, 207 | { 208 | "name": "union" 209 | }, 210 | { 211 | "name": "intersect" 212 | }, 213 | { 214 | "name": "update" 215 | }, 216 | { 217 | "name": "forkey" 218 | }, 219 | { 220 | "name": "copy" 221 | } 222 | ] 223 | }, 224 | { 225 | "module": "Enum", 226 | "doc": "Enumerables", 227 | "methods": [ 228 | { 229 | "name": "foreach" 230 | }, 231 | { 232 | "name": "map" 233 | }, 234 | { 235 | "name": "mapi", 236 | "doc": "the function should take 2 arguements, the first of which is the integer index of the enumerable." 237 | }, 238 | { 239 | "name": "range", 240 | "type": "range : (Int start, Int end, Int sep = 1) -> Enum" 241 | } 242 | ] 243 | } 244 | ] -------------------------------------------------------------------------------- /Diana/CollectionExts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Collections.Generic; 4 | namespace Diana 5 | { 6 | public static partial class CollectionExts 7 | { 8 | 9 | 10 | public static R ReduceRight(this IEnumerable seq, R init, Func ap) 11 | { 12 | R res = init; 13 | foreach(var e in seq.Reverse()) 14 | { 15 | res = ap(res, e); 16 | } 17 | return res; 18 | } 19 | 20 | public static T Pop(this List self) 21 | { 22 | int i = self.Count; 23 | var r = self[i-1]; 24 | self.RemoveAt(i-1); 25 | return r; 26 | } 27 | 28 | public static Dictionary ShallowCopy(this Dictionary self) 29 | { 30 | return new Dictionary(self); 31 | } 32 | 33 | public static V[] ShallowCopy(this V[] self) 34 | { 35 | return self.Clone() as V[]; 36 | } 37 | 38 | public static List ShallowCopy(this List self) 39 | { 40 | return new List(self); 41 | } 42 | 43 | public static void AddAsSet(this Dictionary self, DObj o) 44 | { 45 | self[o] = DNone.unique; 46 | } 47 | 48 | 49 | public static Dictionary UnionDict(this Dictionary self, Dictionary other) 50 | { 51 | self = self.ShallowCopy(); 52 | foreach(var x in other) 53 | { 54 | self[x.Key] = x.Value; 55 | } 56 | return self; 57 | } 58 | 59 | public static Dictionary Union(this Dictionary self, IEnumerable other) 60 | { 61 | self = self.ShallowCopy(); 62 | foreach(var x in other) 63 | { 64 | self[x] = DNone.unique; 65 | } 66 | return self; 67 | } 68 | 69 | public static void Merge(this Dictionary self, Dictionary other) 70 | { 71 | foreach(var x in other) 72 | { 73 | self[x.Key] = x.Value; 74 | } 75 | } 76 | 77 | public static void Merge(this Dictionary self, Dictionary other) 78 | { 79 | foreach(var x in other) 80 | { 81 | self[(string) (DString) x.Key] = x.Value; 82 | } 83 | } 84 | 85 | public static Dictionary dictOf(IEnumerable pairs) 86 | { 87 | var res = new Dictionary(); 88 | foreach(var kv in pairs) 89 | { 90 | var pair = kv as DTuple; 91 | if (pair == null || pair.elts.Length != 2) 92 | throw new ValueError($"invalid key-value pair {kv}"); 93 | 94 | res[pair.elts[0]] = pair.elts[1]; 95 | } 96 | return res; 97 | } 98 | 99 | public static Dictionary setOf(IEnumerable elts) 100 | { 101 | var res = new Dictionary(); 102 | foreach(var elt in elts) 103 | { 104 | res[elt] = DNone.unique; 105 | } 106 | return res; 107 | } 108 | public static Dictionary Intersect(this Dictionary self, IEnumerable other) 109 | { 110 | var res = new Dictionary(); 111 | foreach(var x in other) 112 | { 113 | if (self.ContainsKey(x)) 114 | { 115 | res[x] = DNone.unique; 116 | } 117 | } 118 | return res; 119 | } 120 | 121 | 122 | public static IEnumerable ObjectPairs(this Dictionary self) 123 | { 124 | return self.Select(x => MK.tuple(x.Key, x.Value)); 125 | } 126 | 127 | public static IEnumerable ObjectPairs(this Dictionary self) 128 | { 129 | return self.Select(x => MK.tuple(MK.String(x.Key), x.Value)); 130 | } 131 | public static Dictionary DifferenceDObj(this Dictionary self, DObj other) 132 | { 133 | 134 | var res = new Dictionary(); 135 | 136 | var try_dict = other as DDict; 137 | if(try_dict != null) 138 | { 139 | foreach(var x in self) 140 | { 141 | var dict = try_dict.dict; 142 | if (!dict.ContainsKey(x.Key)) 143 | { 144 | res[x.Key] = DNone.unique; 145 | } 146 | } 147 | return res; 148 | } 149 | var set = other.__iter__().ToHashSet(); 150 | foreach(var x in self) 151 | { 152 | if (!set.Contains(x.Key)) 153 | { 154 | res[x.Key] = DNone.unique; 155 | } 156 | } 157 | return res; 158 | } 159 | 160 | public static void ForEach_(this IEnumerable self, DObj func) 161 | { 162 | var args = new DObj[1]; 163 | foreach(var elt in self) 164 | { 165 | args[0] = elt; 166 | func.__call__(args); 167 | } 168 | } 169 | 170 | public static IEnumerable Map(this IEnumerable self, DObj func) 171 | { 172 | var args = new DObj[1]; 173 | foreach(var elt in self) 174 | { 175 | args[0] = elt; 176 | yield return func.__call__(args); 177 | } 178 | } 179 | 180 | public static IEnumerable MapI(this IEnumerable self, DObj func) 181 | { 182 | var args = new DObj[2]; 183 | var i = 0; 184 | foreach(var elt in self) 185 | { 186 | args[0] = MK.Int(i++); 187 | args[1] = elt; 188 | yield return func.__call__(args); 189 | } 190 | } 191 | 192 | public static void ForEachIndex_(this List self, DObj func) 193 | { 194 | var args = new DObj[1]; 195 | for(var i = 0; i < self.Count; i++) 196 | { 197 | args[0] = MK.Int(i); 198 | func.__call__(args); 199 | } 200 | } 201 | 202 | public static void ForEachIndex_(this DObj[] self, DObj func) 203 | { 204 | var args = new DObj[1]; 205 | for(var i = 0; i < self.Length; i++) 206 | { 207 | args[0] = MK.Int(i); 208 | func.__call__(args); 209 | } 210 | } 211 | 212 | public static void ForEachIndex_(this Dictionary self, DObj func) 213 | { 214 | var args = new DObj[1]; 215 | 216 | foreach(var key in self.Keys) 217 | { 218 | args[0] = key; 219 | func.__call__(args); 220 | } 221 | } 222 | 223 | public static void ForEachIndex_(this Dictionary self, DObj func) 224 | { 225 | var args = new DObj[1]; 226 | 227 | foreach(var key in self.Keys) 228 | { 229 | args[0] = MK.String(key); 230 | func.__call__(args); 231 | } 232 | } 233 | 234 | 235 | public static IEnumerable Range(long start, long end, long sep = 1) 236 | { 237 | 238 | for(long i=start; i Range(long end) 245 | { 246 | for(long i=0; i list['a] 9 | val extend : forall 'a. (list['a], list['a]) -> list['a] 10 | val empty : forall 'a. () -> list['a] 11 | val resolve_binop : (list[object]) -> ImmediateAST 12 | val to_obj : forall 'a. ('a) -> object 13 | val unesc : (str) -> str 14 | val null : forall 'a. 'a 15 | val mkOGet: (token, ast, ast) -> ast 16 | val mkVal: (token, DObj) -> ast 17 | val mkApp: (token, ast, list[ast]) -> ast 18 | val mkList: (token, list[ast]) -> ast 19 | val mkTuple: (token, list[ast], bool) -> ast 20 | val mkDict: (token, list[(ast, ast)]) -> ast 21 | val mkSet: (token, list[ast]) -> ast 22 | val mkVar: (token, str) -> ast 23 | val mkDecl: (token, list[str]) -> ast 24 | val mkInv: (token, ast) -> ast 25 | val mkNeg: (token, ast) -> ast 26 | val mkNot: (token, ast) -> ast 27 | val mkAnd: (token, ast, ast) -> ast 28 | val mkOr: (token, ast, ast) -> ast 29 | val mkIfThen: (token, ast, ast) -> ast 30 | val mkStoreMany: (list[(ast, str)], ast) -> ast 31 | val mkNestedIf: (token, list[(ast, ast)], ast) -> ast 32 | val mkPipeline: (list[ast]) -> ast 33 | val mkFunc: (token, str, list[str], list[ast]) -> ast 34 | val mkLoop: (token, ast) -> ast 35 | val mkFor: (token, str, ast, ast) -> ast 36 | val mkWhile: (token, ast, ast) -> ast 37 | val mkBlock: (token, list[ast]) -> ast 38 | val mkContinue: (token) -> ast 39 | val mkBreak: (token) -> ast 40 | val mkReturn: (token, ast) -> ast 41 | val mkSymbol: (token, str) -> ast 42 | val mkint: (str, int) -> DObj 43 | val mkfloat: (str) -> DObj 44 | val mkstr: (str) -> DObj 45 | val mknone: () -> DObj 46 | val mkop: (token, str) -> object 47 | val true: bool 48 | val false: bool 49 | 50 | start : optional[newline] nullable[seplist[newline, stmt]] optional[newline] 51 | { $2 } 52 | 53 | list[e] : e { [$1] } 54 | | list[e] e { append($1, $2) } 55 | 56 | 57 | seplist[sep, e]: 58 | e { [$1] } 59 | | seplist[sep, e] sep e { append($1, $3) } 60 | 61 | line_wrap[e] : optional[newline] e optional[newline] { $2 } 62 | 63 | 64 | // comsume all newlines inside the quote 65 | _closelist[sep, e]: 66 | _closelist[sep, e] newline { $1 } 67 | | _closelist[sep, e] sep newline e 68 | { append($1, $4) } 69 | | _closelist[sep, e] sep e 70 | { append($1, $3) } 71 | | e { [$1] } 72 | | { [] } 73 | 74 | closelist[sep, e]: optional[newline] _closelist[sep, e] { $2 } 75 | 76 | 77 | nullable[seq] : seq { $1 } 78 | | { empty() } 79 | 80 | optional[a] : a { $1 } 81 | | { null } 82 | 83 | lhs_seq : lhs_seq lhs optional[ibinop] "=" { append($1, ($2, $3)) } 84 | | lhs optional[ibinop] "=" { [($1, $2)] } 85 | | lhs2 "=" { [($1, null)] } 86 | | lhs_seq lhs2 "=" { append($1, ($2, null)) } 87 | 88 | elifBlock : expr blockOf[then] { ($1, $2) } 89 | 90 | snd[a, b] : a b { $2 } 91 | 92 | name : { $1.Text } 93 | stmt : 94 | "var" seplist[",", name] { mkDecl($1, $2) } 95 | | lhs_seq expr { mkStoreMany($1, $2) } 96 | | "loop" block "end" 97 | { mkLoop($1, mkBlock($1, $2)) } 98 | | "while" expr blockOf[do] "end" 99 | { mkWhile($1, $2, $3) } 100 | | "for" "in" expr blockOf[do] "end" 101 | { mkFor($1, $2.Text, $4, $5) } 102 | | expr { $1 } 103 | 104 | 105 | or_[a, b] : a { 0 } 106 | | b { 0 } 107 | 108 | then: optional[newline] "then" { $2 } 109 | do: optional[newline] "do" { $2 } 110 | 111 | lhs : { mkVar($1, $1.Text) } 112 | | atom "." "[" expr "]" 113 | { mkOGet($2, $1, $4) } 114 | | atom "." 115 | { mkOGet($2, $1, mkVal($3, mkstr($3.Text))) } 116 | 117 | or[a, b] : a { $1 } 118 | | b { $1 } 119 | 120 | lhs2 : "(" closelist[",", or[lhs3, lhs2]] trailer ")" { mkTuple($1, $2, $3) } 121 | | "var" { mkDecl($1, [$2.Text]) } 122 | 123 | lhs3 : { mkVar($1, $1.Text) } 124 | 125 | block : filter[stmt, or_[";", newline]] { $1 } 126 | 127 | filter[keep, discard] : 128 | filter[keep, discard] keep { append($1, $2) } 129 | | filter[keep, discard] discard { $1 } 130 | | keep { append(empty(), $1) } 131 | | discard { empty() } 132 | 133 | 134 | expr : or_expr { $1 } 135 | 136 | or_expr : or_expr line_wrap["or"] and_expr 137 | { mkOr($2, $1, $3) } 138 | | and_expr { $1 } 139 | 140 | and_expr : and_expr line_wrap["and"] not 141 | { mkAnd($2, $1, $3) } 142 | | not { $1 } 143 | 144 | not : line_wrap["not"] not { mkNot($1, $2) } 145 | | bin { $1 } 146 | 147 | 148 | 149 | binop : { mkop($1, $1.Text) } 150 | | "not" "in" { mkop($1, "notin") } 151 | | "in" { mkop($1, "in") } 152 | | "-" { mkop($1, "-") } 153 | 154 | ibinop : { $1.Text } 155 | | "-" { "-" } 156 | 157 | binseq : atom { append(empty(), to_obj($1)) } 158 | | binseq binop atom { 159 | append($1, $2); 160 | append($1, to_obj($3)) } 161 | 162 | bin : binseq { resolve_binop($1) } 163 | 164 | trailer : "," { true } 165 | | { false } 166 | 167 | blockOf[a] : a block { mkBlock($1, $2) } 168 | 169 | pair : expr line_wrap[":"] expr { ($1, $3) } 170 | atom : atom "." "[" expr "]" { mkOGet($2, $1, $4) } 171 | | atom "." { mkOGet($2, $1, mkVal($3, mkstr($3.Text))) } 172 | | ":" { mkSymbol($2, $2.Text) } 173 | | ":" { mkSymbol($2, unesc($2.Text)) } 174 | | atom "(" closelist[",", expr] ")" { mkApp($2, $1, $3) } 175 | | "[" closelist[",", expr] "]" { mkList($1, $2) } 176 | | "(" closelist[",", expr] trailer ")" { mkTuple($1, $2, $3) } 177 | | "{" closelist[",", pair] trailer "}" { mkDict($1, $2) } 178 | | "{" closelist[",", expr] "}" { mkSet($1, $2) } 179 | | { mkVal($1, mkstr(unesc($1.Text))) } 180 | | { mkVal($1, mkint($1.Text, 0)) } 181 | | { mkVal($1, mkint($1.Text, 16)) } 182 | | { mkVal($1, mkint($1.Text, 8)) } 183 | | { mkVal($1, mkint($1.Text, 2)) } 184 | | { mkVal($1, mkfloat($1.Text)) } 185 | | "None" { mkVal($1, mknone()) } 186 | | { mkVar($1, $1.Text) } 187 | | "-" atom { mkNeg($1, $2) } 188 | | "~" atom { mkInv($1, $2) } 189 | | "if" expr then block "end" 190 | { mkIfThen($1, $2, mkBlock($3, $4)) } 191 | | "if" expr then block 192 | nullable[list[snd["elif", elifBlock]]] 193 | optional[blockOf["else"]] 194 | "end" 195 | { 196 | let elif = ($2, mkBlock($3, $4)) in 197 | let elifs = append(empty(), elif) in 198 | let elifs = extend(elifs, $5) in 199 | mkNestedIf($1, elifs, $6) 200 | } 201 | | "fun" name "(" nullable[seplist[",", name]] ")" 202 | block 203 | "end" { mkFunc($1, $2, $4, $6) } 204 | | "fun" "(" nullable[seplist[",", name]] ")" 205 | block 206 | "end" { mkFunc($1, "", $3, $5) } 207 | | "(" nullable[seplist[",", name]] ")" "->" line_wrap[expr] 208 | { mkFunc($1, "", $2, [$5]) } 209 | | "->" line_wrap[expr] 210 | { mkFunc($1, "", [$1.Text], [$3]) } 211 | | "break" { mkBreak($1) } 212 | | "continue" { mkContinue($1) } 213 | | "return" expr { mkReturn($1, $2) } 214 | | "return" { mkReturn($1, null) } 215 | 216 | 217 | newline : { $1 } 218 | | newline { $2 } 219 | 220 | %ignore , 221 | 222 | : "#" (!("\n"| "\r"))* 223 | : ("<" | ">" |">=" | "<=" | "==" | "!=" | "+" | "*" | "**" | "/" | "//" | "%" | "&" | "|" | "<<" | ">>") 224 | : "\\\"" 225 | : "\"" ( ESCAPED_QUOTE | !"\"")* "\"" 226 | : ("\r" | "\t" | "\n" | " ") 227 | 228 | : (DIGIT+ | HEX | OCT | BIN) 229 | : "0x" ([0-9] | [a-f])* 230 | : "0o" [0-7]* 231 | : "0b" [0-1]* 232 | 233 | : [0-9] 234 | : INT "." INT 235 | : [a-z] | [A-Z] | "_" | [\u4e00-\u9fa5] | "\u2606" 236 | : UCODE (DIGIT | UCODE)* 237 | : (" " | "\t")+ 238 | : "\r" 239 | : "\n" 240 | : (CR? LF)+ (WS_INLINE | (CR? LF))* -------------------------------------------------------------------------------- /docs.md: -------------------------------------------------------------------------------- 1 | ## 语法Cheat Sheet 2 | 3 | ```ruby 4 | # this is a comment 5 | k = x[1] = 3 # multi-target assignment 6 | 7 | 8 | # variable declaration. 9 | # if no declaration in scope, regarded as a global variable. 10 | var x 11 | 12 | 13 | x = 0 14 | loop 15 | # if .. then ... end 16 | if x > 100 then 17 | break 18 | end 19 | x += 1 20 | end 21 | 22 | # above loop is equivalent to 23 | 24 | x = 0 25 | while x <= 100 do 26 | x += 1 27 | end 28 | 29 | # for loop 30 | for i in Enum.range(20) do 31 | log(i) # of course you can use 'break' and 'continue' 32 | end 33 | # 0 34 | # 1 35 | # ... 36 | # 19 37 | 38 | x = [1, 2, 3] # mutable list 39 | 40 | x[0] # 1 41 | x[1] = 3 # x == [1, 3, 3] 42 | 43 | x = (1, ) # tuple 44 | x > (0, 1) # return 1(means 'true') 45 | x > (1, 1) # return 0(means 'false') 46 | 47 | x = {} # set,as well as a None-value dictionary 48 | x[1] = None 49 | log(x) # {1} 50 | 51 | x[2] = 10; log(x) # {1, 2:10} 52 | 53 | x.attr = 20 # equivalent to '["attr"] = 20' 54 | log(x) # {1, 2:10, "attr": 20} 55 | 56 | z = if 1 then 0 else 1 end # if-expression 57 | 58 | # multi-arm if-expression 59 | if cond1 then 60 | 1 61 | elif cond2 then 62 | 2 63 | elif cond3 then 64 | 3 65 | else 66 | 4 67 | end 68 | 69 | 70 | # function 71 | fun add(x, y) 72 | x + y # no need to explicitly return here 73 | end 74 | 75 | # function is a value 76 | add = fun (x, y) 77 | x + y 78 | end 79 | 80 | # if your function body is an expression 81 | mul10 = x -> x * 10 82 | ``` 83 | 84 | ## Basic Types 85 | 86 | In C# side, every thing in DianaScript is an instance whose class interfaces `DObj`. 87 | 88 | You can access `DObj.Native` to access their .NET representation: 89 | 90 | | Types | .NET representation | Literal Examples | 91 | | --- | --- | --- | 92 | | Int | int64(System.Int64) | `1, 0xef, 0b01, 0o33` | 93 | | Num | float32(System.Single) | `1.0` | 94 | | Str | string(unicode-16 string) | `"ava"`, `"bela\\"la"` | 95 | | Dict | Dictionary\ | `{1: 2, "3": 4}`, `{1, 2, 3}`(just like sets) | 96 | | List | List\ | `[1, 2, if 1 then 2 else 3 end]` | 97 | | Tuple | DObj[](immutable in Diana) | `(1, ), (1, 2), (,), ()` | 98 | | Enum | IEnumerable\ | `List.map([1, 2], x -> x + 10)` | 99 | | None | an empty struct `DNone` | `None` | 100 | | Func | functions | `x -> x, fun myfunc(x) return x end` | 101 | 102 | 103 | ## Operators 104 | 105 | `**` is right-associative. 106 | 107 | 108 | | Operators | Descrption | Supported Types | Precedence | 109 | |--|--| --| -- | 110 | |+| addition | `Int, Num, List(concat), Tuple(concat)` | 7 | 111 | |-| subtraction | `Int, Num, Dict(set difference)` | 7 | 112 | |*| multiplication | `Int, Num, Str(repeat)` | 8 | 113 | |**| power | `Int, Num` | 9 | 114 | |/|float division | `Int, Num, Dict(quotient set)` | 8 | 115 | |//|floor division(get integer) | `Int, Num` | 8 | 116 | |%| modulo(not remainder) | `Int, Num` | 8 | 117 | |^| bitwise xor | `Int, Num` | 4 | 118 | |&| bitwise and/intersect | `Int, Num, Dict(set intersect)` | 5 | 119 | |\|| bitwise or/union | `Int, Num, Dict(set union)` | 3 | 120 | |!=| non-equality | All | 2 | 121 | |==| equality | All | 2 | 122 | |>, <, >=, <=| inequality | `Int, Num, Tuple` | 2 | 123 | | ~ | bit invert | `Int` | MAX | 124 | | - | unary minus | `Int, Num` | MAX | 125 | | not | negation | any | MAX | 126 | | << | left shift | `Int`(higher bits are circular) | 6 | 127 | | >> | zero-fill right shift | `Int`(discard lower bits) | 6 | 128 | | not in/in | check if/if not contained | any in/not in `List/Set/Tuple/String` | 2 | 129 | 130 | ## Modules and Methods 131 | 132 | ### `Int` 133 | 134 | - `Int.get_max()`: get max value of int64 135 | - `Int.get_min()`: get min value of int64 136 | - `Int.of(Str | Int | Num)`: convert to `Int`, from `Str`, `Int` or `Num` 137 | 138 | 139 | ### `Num` 140 | 141 | - `Num.get_max`: get max of float32 value 142 | - `Num.get_min`: get min of float32 value 143 | - `Num.of(Str | Int | Num)`: convert to `Num`, from `Str`, `Int` or `Num` 144 | 145 | ### `Str` 146 | 147 | We omit the return type when it is `Str`. 148 | 149 | - `Str.of(any)`: convert any to `Str` 150 | - `Str.join(Str, Enum)` 151 | - `Str.concat(Enum)` 152 | - `Str.endswith(Str, Str)` 153 | - `Str.startswith(Str, Str)` 154 | - `Str.len(Str): Int` 155 | - `Str.strip(Str, Str?)` 156 | 157 | wrap of `Systen.String.Trim`; when the second argument is not provided, trim left and right whitespaces. 158 | 159 | - `Str.lstrip(Str, Str?)` 160 | 161 | wrap of `Systen.String.TrimStart`; when the second argument is not provided, trim left whitespaces. 162 | 163 | - `Str.rstrip(Str, Str?)` 164 | wrap of `Systen.String.TrimEnd`; when the second argument is not provided, trim right whitespaces. 165 | 166 | - `Str.lower(Str)`, `Str.upper(Str)` 167 | wrap of `Systen.String.ToLowerInvariant/ToUpperInvariant` 168 | 169 | - `Str.contains(String): Int` : return 0 if false, or 1 if true 170 | 171 | - `Str.format(Str, any1, any2, ...)`: equivalent to `System.String.Format` in .NET. 172 | 173 | - `Str.substr(Str, Int, Int?)` 174 | 175 | wrap of `Systen.String.Substring`; **the third argument is the length** of the substring 176 | 177 | 178 | - `Str.insert(Str, Int, Str)` 179 | 180 | wrap of `Systen.String.Insert` 181 | 182 | - `Str.remove_at(Str, Int, Str)` 183 | 184 | wrap of `Systen.String.Remove` 185 | 186 | - `Str.index(Str, Str, Int?, Int?)` 187 | 188 | wrap of `Systen.String.IndexOf` 189 | 190 | 191 | ## Tuple 192 | 193 | A `Tuple` is an `Enum`. 194 | 195 | - `Tuple.of(Enum): Tuple`: convert any enumerable of diana objects to a tuple 196 | - `Tuple.len(Tuple): Int` 197 | - `Tuple.forkey(Tuple, function): None` 198 | 199 | ```elixir 200 | xs = (2, 4, 6) 201 | Tuple.forkey(log) 202 | # 0 203 | # 1 204 | # 2 205 | 206 | # you might use 'Enum.foreach(xs, log)' for this 207 | Tuple.forkey(i -> log(xs[i])) 208 | # 2 209 | # 4 210 | # 5 211 | ``` 212 | ## List 213 | 214 | - `List.of(Enum): List`: `Enum` to `List` 215 | - `List.push(List, any)` 216 | - `List.pop(List): any` 217 | - `List.extend(List, Enum)` 218 | - `List.clear(List)` 219 | - `List.find(List, function)` 220 | 221 | ```elixir 222 | List.find([1, 6, 3], x -> x % 2 == 0) 223 | # 6 224 | 225 | List.find([1, 6, 3], x -> x > 20) 226 | # None 227 | ``` 228 | - `List.index(List, any, Int?)` 229 | 230 | wrap of `System.Collections.Generic.List.IndexOf` 231 | 232 | - `List.remove_at(List, Int)` 233 | 234 | wrap of `System.Collections.Generic.List.RemoveAt` 235 | 236 | - `List.forkey(List, function)` 237 | 238 | ```julia 239 | var lst 240 | lst = [1, 2, 3] 241 | List.forkey(lst, i -> func(lst[i])) # == 'Enum.foreach(lst, func)' 242 | ``` 243 | 244 | - item index operator: 245 | 246 | ```lua 247 | x = [1, 2, 3] 248 | x[1] 249 | x[1] = 2 250 | ``` 251 | 252 | - `in`, `not in`: `elt in lst == not (elt not in lst)` 253 | 254 | ## Dict 255 | 256 | `Dict` is also `Set`; a `Set` is a `Dict` whose values are `None`. 257 | 258 | - `Dict.of(Enum): Dict`: from an enumerable of 2-element tuple to a dictionary 259 | - `Dict.setOf(Enum): Dict`: construct a set from an enumerable 260 | - `Dict.remove(Dict, any key): None` 261 | - `Dict.clear(Dict)` 262 | - `Dict.len(Dict): int` 263 | - `Dict.len(Dict): int` 264 | - `Dict.contains(Dict d, any key): Int`: same as `key in d` or `not (key not in d)` 265 | - `Dict.search(Dict, any key, List ref): Int` 266 | 267 | wrap of `System.Collections.Generic.Dictionary.TryGetValue`. 268 | 269 | return 1 if key is found, and set the first element of argument `ref` to the value; otherwise return 0. 270 | 271 | ```python 272 | found_ref = [None] 273 | Dict.search({"key": "value"} 1, found_ref) # 1 274 | found_ref # ["value"] 275 | ``` 276 | 277 | - `Dict.subtract(Dict, Enum)`: same as `-` operator for dictionaries; set difference 278 | 279 | ```python 280 | x = {1, 2, 3} 281 | Dict.subtract(x, [1, 2]) # {3} 282 | ``` 283 | 284 | - `Dict.union(Dict, Enum)`: same as `|` operator for dictionaries; set union 285 | 286 | - `Dict.intersect(Dict, Enum)`: same as `&` operator for dictionaries; set intersect 287 | 288 | - `Dict.update(Dict, Dict)`: update the first dict with key-values pairs in the second dict 289 | - `Dict.forkey(Dict, function)` 290 | 291 | 292 | ## Enum 293 | 294 | - `Enum.foreach(Enum, func): None` 295 | 296 | - `Enum.map(Enum, func): Enum` 297 | 298 | - `Enum.mapi(Enum, func): Enum` : the function should take 2 arguements, the first of which is the integer index of the enumerable. 299 | - `Enum.range(Int start, Int end, Int sep)` 300 | - `Enum.range(Int n)` 301 | 302 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # generated ran code and antlr files 7 | *.tokens 8 | *.interp 9 | .antlr/ 10 | 11 | # generated Python code 12 | codegen/*_raw.py 13 | 14 | .idea/ 15 | .vscode/ 16 | runtests/mylang_raw.py 17 | docs/_build 18 | 19 | # User-specific files 20 | *.rsuser 21 | *.suo 22 | *.user 23 | *.userosscache 24 | *.sln.docstates 25 | 26 | # User-specific files (MonoDevelop/Xamarin Studio) 27 | *.userprefs 28 | 29 | # Mono auto generated files 30 | mono_crash.* 31 | 32 | # Build results 33 | [Dd]ebug/ 34 | [Dd]ebugPublic/ 35 | [Rr]elease/ 36 | [Rr]eleases/ 37 | x64/ 38 | x86/ 39 | [Ww][Ii][Nn]32/ 40 | [Aa][Rr][Mm]/ 41 | [Aa][Rr][Mm]64/ 42 | bld/ 43 | [Bb]in/ 44 | [Oo]bj/ 45 | [Ll]og/ 46 | [Ll]ogs/ 47 | 48 | # Visual Studio 2015/2017 cache/options directory 49 | .vs/ 50 | # Uncomment if you have tasks that create the project's static files in wwwroot 51 | #wwwroot/ 52 | 53 | # Visual Studio 2017 auto generated files 54 | Generated\ Files/ 55 | 56 | # MSTest test Results 57 | [Tt]est[Rr]esult*/ 58 | [Bb]uild[Ll]og.* 59 | 60 | # NUnit 61 | *.VisualState.xml 62 | TestResult.xml 63 | nunit-*.xml 64 | 65 | # Build Results of an ATL Project 66 | [Dd]ebugPS/ 67 | [Rr]eleasePS/ 68 | dlldata.c 69 | 70 | # Benchmark Results 71 | BenchmarkDotNet.Artifacts/ 72 | 73 | # .NET Core 74 | project.lock.json 75 | project.fragment.lock.json 76 | artifacts/ 77 | 78 | # ASP.NET Scaffolding 79 | ScaffoldingReadMe.txt 80 | 81 | # StyleCop 82 | StyleCopReport.xml 83 | 84 | # Files built by Visual Studio 85 | *_i.c 86 | *_p.c 87 | *_h.h 88 | *.ilk 89 | *.meta 90 | *.obj 91 | *.iobj 92 | *.pch 93 | *.pdb 94 | *.ipdb 95 | *.pgc 96 | *.pgd 97 | *.rsp 98 | *.sbr 99 | *.tlb 100 | *.tli 101 | *.tlh 102 | *.tmp 103 | *.tmp_proj 104 | *_wpftmp.csproj 105 | *.log 106 | *.tlog 107 | *.vspscc 108 | *.vssscc 109 | .builds 110 | *.pidb 111 | *.svclog 112 | *.scc 113 | 114 | # Chutzpah Test files 115 | _Chutzpah* 116 | 117 | # Visual C++ cache files 118 | ipch/ 119 | *.aps 120 | *.ncb 121 | *.opendb 122 | *.opensdf 123 | *.sdf 124 | *.cachefile 125 | *.VC.db 126 | *.VC.VC.opendb 127 | 128 | # Visual Studio profiler 129 | *.psess 130 | *.vsp 131 | *.vspx 132 | *.sap 133 | 134 | # Visual Studio Trace Files 135 | *.e2e 136 | 137 | # TFS 2012 Local Workspace 138 | $tf/ 139 | 140 | # Guidance Automation Toolkit 141 | *.gpState 142 | 143 | # ReSharper is a .NET coding add-in 144 | _ReSharper*/ 145 | *.[Rr]e[Ss]harper 146 | *.DotSettings.user 147 | 148 | # TeamCity is a build add-in 149 | _TeamCity* 150 | 151 | # DotCover is a Code Coverage Tool 152 | *.dotCover 153 | 154 | # AxoCover is a Code Coverage Tool 155 | .axoCover/* 156 | !.axoCover/settings.json 157 | 158 | # Coverlet is a free, cross platform Code Coverage Tool 159 | coverage*.json 160 | coverage*.xml 161 | coverage*.info 162 | 163 | # Visual Studio code coverage results 164 | *.coverage 165 | *.coveragexml 166 | 167 | # NCrunch 168 | _NCrunch_* 169 | .*crunch*.local.xml 170 | nCrunchTemp_* 171 | 172 | # MightyMoose 173 | *.mm.* 174 | AutoTest.Net/ 175 | 176 | # Web workbench (sass) 177 | .sass-cache/ 178 | 179 | # Installshield output folder 180 | [Ee]xpress/ 181 | 182 | # DocProject is a documentation generator add-in 183 | DocProject/buildhelp/ 184 | DocProject/Help/*.HxT 185 | DocProject/Help/*.HxC 186 | DocProject/Help/*.hhc 187 | DocProject/Help/*.hhk 188 | DocProject/Help/*.hhp 189 | DocProject/Help/Html2 190 | DocProject/Help/html 191 | 192 | # Click-Once directory 193 | publish/ 194 | 195 | # Publish Web Output 196 | *.[Pp]ublish.xml 197 | *.azurePubxml 198 | # Note: Comment the next line if you want to checkin your web deploy settings, 199 | # but database connection strings (with potential passwords) will be unencrypted 200 | *.pubxml 201 | *.publishproj 202 | 203 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 204 | # checkin your Azure Web App publish settings, but sensitive information contained 205 | # in these scripts will be unencrypted 206 | PublishScripts/ 207 | 208 | # NuGet Packages 209 | *.nupkg 210 | # NuGet Symbol Packages 211 | *.snupkg 212 | # The packages folder can be ignored because of Package Restore 213 | **/[Pp]ackages/* 214 | # except build/, which is used as an MSBuild target. 215 | !**/[Pp]ackages/build/ 216 | # Uncomment if necessary however generally it will be regenerated when needed 217 | #!**/[Pp]ackages/repositories.config 218 | # NuGet v3's project.json files produces more ignorable files 219 | *.nuget.props 220 | *.nuget.targets 221 | 222 | # Nuget personal access tokens and Credentials 223 | nuget.config 224 | 225 | # Microsoft Azure Build Output 226 | csx/ 227 | *.build.csdef 228 | 229 | # Microsoft Azure Emulator 230 | ecf/ 231 | rcf/ 232 | 233 | # Windows Store app package directories and files 234 | AppPackages/ 235 | BundleArtifacts/ 236 | Package.StoreAssociation.xml 237 | _pkginfo.txt 238 | *.appx 239 | *.appxbundle 240 | *.appxupload 241 | 242 | # Visual Studio cache files 243 | # files ending in .cache can be ignored 244 | *.[Cc]ache 245 | # but keep track of directories ending in .cache 246 | !?*.[Cc]ache/ 247 | 248 | # Others 249 | ClientBin/ 250 | ~$* 251 | *~ 252 | *.dbmdl 253 | *.dbproj.schemaview 254 | *.jfm 255 | *.pfx 256 | *.publishsettings 257 | orleans.codegen.cs 258 | 259 | # Including strong name files can present a security risk 260 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 261 | #*.snk 262 | 263 | # Since there are multiple workflows, uncomment next line to ignore bower_components 264 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 265 | #bower_components/ 266 | 267 | # RIA/Silverlight projects 268 | Generated_Code/ 269 | 270 | # Backup & report files from converting an old project file 271 | # to a newer Visual Studio version. Backup files are not needed, 272 | # because we have git ;-) 273 | _UpgradeReport_Files/ 274 | Backup*/ 275 | UpgradeLog*.XML 276 | UpgradeLog*.htm 277 | ServiceFabricBackup/ 278 | *.rptproj.bak 279 | 280 | # SQL Server files 281 | *.mdf 282 | *.ldf 283 | *.ndf 284 | 285 | # Business Intelligence projects 286 | *.rdl.data 287 | *.bim.layout 288 | *.bim_*.settings 289 | *.rptproj.rsuser 290 | *- [Bb]ackup.rdl 291 | *- [Bb]ackup ([0-9]).rdl 292 | *- [Bb]ackup ([0-9][0-9]).rdl 293 | 294 | # Microsoft Fakes 295 | FakesAssemblies/ 296 | 297 | # GhostDoc plugin setting file 298 | *.GhostDoc.xml 299 | 300 | # Node.js Tools for Visual Studio 301 | .ntvs_analysis.dat 302 | node_modules/ 303 | 304 | # Visual Studio 6 build log 305 | *.plg 306 | 307 | # Visual Studio 6 workspace options file 308 | *.opt 309 | 310 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 311 | *.vbw 312 | 313 | # Visual Studio LightSwitch build output 314 | **/*.HTMLClient/GeneratedArtifacts 315 | **/*.DesktopClient/GeneratedArtifacts 316 | **/*.DesktopClient/ModelManifest.xml 317 | **/*.Server/GeneratedArtifacts 318 | **/*.Server/ModelManifest.xml 319 | _Pvt_Extensions 320 | 321 | # Paket dependency manager 322 | .paket/paket.exe 323 | paket-files/ 324 | 325 | # FAKE - F# Make 326 | .fake/ 327 | 328 | # CodeRush personal settings 329 | .cr/personal 330 | 331 | # Python Tools for Visual Studio (PTVS) 332 | __pycache__/ 333 | *.pyc 334 | 335 | # Cake - Uncomment if you are using it 336 | # tools/** 337 | # !tools/packages.config 338 | 339 | # Tabs Studio 340 | *.tss 341 | 342 | # Telerik's JustMock configuration file 343 | *.jmconfig 344 | 345 | # BizTalk build output 346 | *.btp.cs 347 | *.btm.cs 348 | *.odx.cs 349 | *.xsd.cs 350 | 351 | # OpenCover UI analysis results 352 | OpenCover/ 353 | 354 | # Azure Stream Analytics local run output 355 | ASALocalRun/ 356 | 357 | # MSBuild Binary and Structured Log 358 | *.binlog 359 | 360 | # NVidia Nsight GPU debugger configuration file 361 | *.nvuser 362 | 363 | # MFractors (Xamarin productivity tool) working folder 364 | .mfractor/ 365 | 366 | # Local History for Visual Studio 367 | .localhistory/ 368 | 369 | # BeatPulse healthcheck temp database 370 | healthchecksdb 371 | 372 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 373 | MigrationBackup/ 374 | 375 | # Ionide (cross platform F# VS Code tools) working folder 376 | .ionide/ 377 | 378 | # Fody - auto-generated XML schema 379 | FodyWeavers.xsd 380 | 381 | # VS Code files for those working on multiple tools 382 | .vscode/* 383 | !.vscode/settings.json 384 | !.vscode/tasks.json 385 | !.vscode/launch.json 386 | !.vscode/extensions.json 387 | *.code-workspace 388 | 389 | # Local History for Visual Studio Code 390 | .history/ 391 | 392 | # Windows Installer files from build outputs 393 | *.cab 394 | *.msi 395 | *.msix 396 | *.msm 397 | *.msp 398 | 399 | # JetBrains Rider 400 | .idea/ 401 | *.sln.iml 402 | typings/ 403 | -------------------------------------------------------------------------------- /Diana.Generated/Methods.DList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq;using System.Collections.Generic; 3 | namespace Diana 4 | { 5 | public partial class DList 6 | { 7 | public string Classname => "List"; 8 | public static DModule module_instance {get; private set;} 9 | public static DObj bind_push(DObj[] _args) // bind method 10 | { 11 | var nargs = _args.Length; 12 | if (nargs != 2) 13 | throw new ArgumentException($"calling List.push; needs at least (2) arguments, got {nargs}."); 14 | var _arg0 = MK.unbox(THint>.val, _args[0]); 15 | var _arg1 = MK.unbox(THint.val, _args[1]); 16 | { 17 | _arg0.Add(_arg1); 18 | return MK.None(); 19 | } 20 | throw new ArgumentException($"call List.push; needs at most (2) arguments, got {nargs}."); 21 | } 22 | public static DObj bind_extend(DObj[] _args) // bind method 23 | { 24 | var nargs = _args.Length; 25 | if (nargs != 2) 26 | throw new ArgumentException($"calling List.extend; needs at least (2) arguments, got {nargs}."); 27 | var _arg0 = MK.unbox(THint>.val, _args[0]); 28 | var _arg1 = MK.unbox(THint>.val, _args[1]); 29 | { 30 | _arg0.AddRange(_arg1); 31 | return MK.None(); 32 | } 33 | throw new ArgumentException($"call List.extend; needs at most (2) arguments, got {nargs}."); 34 | } 35 | public static DObj bind_insert(DObj[] _args) // bind method 36 | { 37 | var nargs = _args.Length; 38 | if (nargs != 3) 39 | throw new ArgumentException($"calling List.insert; needs at least (3) arguments, got {nargs}."); 40 | var _arg0 = MK.unbox(THint>.val, _args[0]); 41 | var _arg1 = MK.unbox(THint.val, _args[1]); 42 | var _arg2 = MK.unbox(THint.val, _args[2]); 43 | { 44 | _arg0.Insert(_arg1,_arg2); 45 | return MK.None(); 46 | } 47 | throw new ArgumentException($"call List.insert; needs at most (3) arguments, got {nargs}."); 48 | } 49 | public static DObj bind_remove(DObj[] _args) // bind method 50 | { 51 | var nargs = _args.Length; 52 | if (nargs != 2) 53 | throw new ArgumentException($"calling List.remove; needs at least (2) arguments, got {nargs}."); 54 | var _arg0 = MK.unbox(THint>.val, _args[0]); 55 | var _arg1 = MK.unbox(THint.val, _args[1]); 56 | { 57 | _arg0.Remove(_arg1); 58 | return MK.None(); 59 | } 60 | throw new ArgumentException($"call List.remove; needs at most (2) arguments, got {nargs}."); 61 | } 62 | public static DObj bind_pop(DObj[] _args) // bind method 63 | { 64 | var nargs = _args.Length; 65 | if (nargs != 1) 66 | throw new ArgumentException($"calling List.pop; needs at least (1) arguments, got {nargs}."); 67 | var _arg0 = MK.unbox(THint>.val, _args[0]); 68 | { 69 | var _return = _arg0.Pop(); 70 | return MK.create(_return); 71 | } 72 | throw new ArgumentException($"call List.pop; needs at most (1) arguments, got {nargs}."); 73 | } 74 | public static DObj bind_find(DObj[] _args) // bind method 75 | { 76 | var nargs = _args.Length; 77 | if (nargs != 2) 78 | throw new ArgumentException($"calling List.find; needs at least (2) arguments, got {nargs}."); 79 | var _arg0 = MK.unbox(THint>.val, _args[0]); 80 | var _arg1 = MK.unbox(THint>.val, _args[1]); 81 | { 82 | var _return = _arg0.Find(_arg1); 83 | return MK.create(_return); 84 | } 85 | throw new ArgumentException($"call List.find; needs at most (2) arguments, got {nargs}."); 86 | } 87 | public static DObj bind_index(DObj[] _args) // bind method 88 | { 89 | var nargs = _args.Length; 90 | if (nargs < 2) 91 | throw new ArgumentException($"calling List.index; needs at least (2,3) arguments, got {nargs}."); 92 | var _arg0 = MK.unbox(THint>.val, _args[0]); 93 | var _arg1 = MK.unbox(THint.val, _args[1]); 94 | if (nargs == 2) 95 | { 96 | _arg0.IndexOf(_arg1); 97 | return MK.None(); 98 | } 99 | var _arg2 = MK.unbox(THint.val, _args[2]); 100 | { 101 | _arg0.IndexOf(_arg1,_arg2); 102 | return MK.None(); 103 | } 104 | throw new ArgumentException($"call List.index; needs at most (3) arguments, got {nargs}."); 105 | } 106 | public static DObj bind_remove_at(DObj[] _args) // bind method 107 | { 108 | var nargs = _args.Length; 109 | if (nargs != 2) 110 | throw new ArgumentException($"calling List.remove_at; needs at least (2) arguments, got {nargs}."); 111 | var _arg0 = MK.unbox(THint>.val, _args[0]); 112 | var _arg1 = MK.unbox(THint.val, _args[1]); 113 | { 114 | _arg0.RemoveAt(_arg1); 115 | return MK.None(); 116 | } 117 | throw new ArgumentException($"call List.remove_at; needs at most (2) arguments, got {nargs}."); 118 | } 119 | public static DObj bind_sort(DObj[] _args) // bind method 120 | { 121 | var nargs = _args.Length; 122 | if (nargs != 1) 123 | throw new ArgumentException($"calling List.sort; needs at least (1) arguments, got {nargs}."); 124 | var _arg0 = MK.unbox(THint>.val, _args[0]); 125 | { 126 | _arg0.Sort(); 127 | return MK.None(); 128 | } 129 | throw new ArgumentException($"call List.sort; needs at most (1) arguments, got {nargs}."); 130 | } 131 | public static DObj bind_array(DObj[] _args) // bind method 132 | { 133 | var nargs = _args.Length; 134 | if (nargs != 1) 135 | throw new ArgumentException($"calling List.array; needs at least (1) arguments, got {nargs}."); 136 | var _arg0 = MK.unbox(THint>.val, _args[0]); 137 | { 138 | var _return = _arg0.ToArray(); 139 | return MK.create(_return); 140 | } 141 | throw new ArgumentException($"call List.array; needs at most (1) arguments, got {nargs}."); 142 | } 143 | public static DObj bind_clear(DObj[] _args) // bind method 144 | { 145 | var nargs = _args.Length; 146 | if (nargs != 1) 147 | throw new ArgumentException($"calling List.clear; needs at least (1) arguments, got {nargs}."); 148 | var _arg0 = MK.unbox(THint>.val, _args[0]); 149 | { 150 | _arg0.Clear(); 151 | return MK.None(); 152 | } 153 | throw new ArgumentException($"call List.clear; needs at most (1) arguments, got {nargs}."); 154 | } 155 | public static DObj bind_of(DObj[] _args) // bind method 156 | { 157 | var nargs = _args.Length; 158 | if (nargs != 1) 159 | throw new ArgumentException($"calling List.of; needs at least (1) arguments, got {nargs}."); 160 | var _arg0 = MK.unbox(THint>.val, _args[0]); 161 | { 162 | var _return = _arg0.ToList(); 163 | return MK.create(_return); 164 | } 165 | throw new ArgumentException($"call List.of; needs at most (1) arguments, got {nargs}."); 166 | } 167 | public static DObj bind_forkey(DObj[] _args) // bind method 168 | { 169 | var nargs = _args.Length; 170 | if (nargs != 2) 171 | throw new ArgumentException($"calling List.forkey; needs at least (2) arguments, got {nargs}."); 172 | var _arg0 = MK.unbox(THint>.val, _args[0]); 173 | var _arg1 = MK.unbox(THint.val, _args[1]); 174 | { 175 | _arg0.ForEachIndex_(_arg1); 176 | return MK.None(); 177 | } 178 | throw new ArgumentException($"call List.forkey; needs at most (2) arguments, got {nargs}."); 179 | } 180 | public static DObj bind_copy(DObj[] _args) // bind method 181 | { 182 | var nargs = _args.Length; 183 | if (nargs != 1) 184 | throw new ArgumentException($"calling List.copy; needs at least (1) arguments, got {nargs}."); 185 | var _arg0 = MK.unbox(THint>.val, _args[0]); 186 | { 187 | var _return = _arg0.ShallowCopy(); 188 | return MK.create(_return); 189 | } 190 | throw new ArgumentException($"call List.copy; needs at most (1) arguments, got {nargs}."); 191 | } 192 | static DList() 193 | { 194 | module_instance = new DModule("List"); 195 | module_instance.fields.Add("push", MK.FuncN("List.push", bind_push)); 196 | module_instance.fields.Add("extend", MK.FuncN("List.extend", bind_extend)); 197 | module_instance.fields.Add("insert", MK.FuncN("List.insert", bind_insert)); 198 | module_instance.fields.Add("remove", MK.FuncN("List.remove", bind_remove)); 199 | module_instance.fields.Add("pop", MK.FuncN("List.pop", bind_pop)); 200 | module_instance.fields.Add("find", MK.FuncN("List.find", bind_find)); 201 | module_instance.fields.Add("index", MK.FuncN("List.index", bind_index)); 202 | module_instance.fields.Add("remove_at", MK.FuncN("List.remove_at", bind_remove_at)); 203 | module_instance.fields.Add("sort", MK.FuncN("List.sort", bind_sort)); 204 | module_instance.fields.Add("array", MK.FuncN("List.array", bind_array)); 205 | module_instance.fields.Add("clear", MK.FuncN("List.clear", bind_clear)); 206 | module_instance.fields.Add("of", MK.FuncN("List.of", bind_of)); 207 | module_instance.fields.Add("forkey", MK.FuncN("List.forkey", bind_forkey)); 208 | module_instance.fields.Add("copy", MK.FuncN("List.copy", bind_copy)); 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /Diana.Frontend/DianaScriptParser.Interface.cs: -------------------------------------------------------------------------------- 1 | using Antlr4.Runtime; 2 | using Antlr4.Runtime.Tree; 3 | using System.Collections.Generic; 4 | using System; 5 | using System.Linq; 6 | using System.Text.RegularExpressions; 7 | 8 | using ast = Diana.ImmediateAST; 9 | namespace Diana.Frontend 10 | { 11 | public struct Pos 12 | { 13 | public int lineno; 14 | public int colno; 15 | public string filename; 16 | } 17 | 18 | public partial class DianaScriptParser 19 | { 20 | public static OperatorResolver<(int, int, string), ast> operatorSolver = new OperatorResolver<(int lineno, int colno, string opname), ast>( 21 | (tpl, l, r) => Bin.make(l, tpl.opname, r, tpl.lineno, tpl.colno) 22 | ); 23 | 24 | public static List append(List lst, A a) 25 | { 26 | lst.Add(a); 27 | return lst; 28 | } 29 | 30 | public static List extend(List lst, List a) 31 | { 32 | lst.AddRange(a); 33 | return lst; 34 | } 35 | public static List empty() 36 | { 37 | return new List(); 38 | } 39 | 40 | public static ast resolve_binop(List ops) 41 | { 42 | if (ops.Count == 1) 43 | { 44 | return (ast)ops[0]; 45 | } 46 | return operatorSolver.binopReduce(ops); 47 | } 48 | 49 | public static object to_obj(A o) => o; 50 | public static string unesc(string s) => 51 | Regex.Unescape(s.Substring(1, s.Length - 2)); 52 | 53 | public static Pos posOfToken(CommonToken token) => new Pos { lineno = token.Line, colno = token.Column, filename = token.TokenSource.SourceName }; 54 | public static ast mkOGet(CommonToken token, ast ast1, ast ast2) 55 | => OGet.make(ast1, ast2, token.Line, token.Column); 56 | 57 | public static ast mkApp(CommonToken token, ast f, List args) 58 | => Call.make(f, args.ToArray(), token.Line, token.Column); 59 | 60 | public static ast mkList(CommonToken token, List elts) 61 | => CList.make(elts.ToArray(), token.Line, token.Column); 62 | 63 | public static ast mkTuple(CommonToken token, List elts, bool has_trailer) 64 | => 65 | (elts.Count == 1 && !has_trailer) ? 66 | elts[0] : 67 | CTuple.make(elts.ToArray(), token.Line, token.Column); 68 | 69 | public static ast mkDict(CommonToken token, List<(ast, ast)> elts) 70 | => CDict.make(elts.ToArray(), token.Line, token.Column); 71 | 72 | public static ast mkSet(CommonToken token, List elts) 73 | => CSet.make(elts.ToArray(), token.Line, token.Column); 74 | 75 | public static ast mkSetMeta(CommonToken token, string idx, string filename) 76 | => SetMeta.make(int.Parse(idx), unesc(filename), token.Line, token.Column); 77 | 78 | // public static ast mkStrDict(CommonToken token, List<(ast, ast)> elts) 79 | // => CStrDict.make(elts.ToArray(), token.Line, token.Column); 80 | 81 | public static ast mkMeta(string idx, string l, string c, ast inner) 82 | => Meta.make(int.Parse(idx), inner, int.Parse(l), int.Parse(c)); 83 | 84 | public static ast mkVar(CommonToken token, string name) 85 | => Load.make(name, token.Line, token.Column); 86 | 87 | public static ast mkVal(CommonToken token, DObj o) 88 | => CVal.make(o, token.Line, token.Column); 89 | 90 | public static ast mkSymbol(CommonToken token, string name) 91 | => Symbol.make(name, token.Line, token.Column); 92 | 93 | // public static ast mkIBin(CommonToken token, ImmediateAST target, string op, ImmediateAST value) 94 | // => IBin.make(target, op, value, token.Line, token.Column); 95 | 96 | public static ast mkInv(CommonToken token, ast ast) 97 | => Inv.make(ast, token.Line, token.Column); 98 | 99 | public static ast mkNeg(CommonToken token, ast ast) 100 | => Neg.make(ast, token.Line, token.Column); 101 | 102 | public static ast mkNot(CommonToken token, ast ast) 103 | => Not.make(ast, token.Line, token.Column); 104 | 105 | public static ast mkAnd(CommonToken token, ast ast1, ast ast2) 106 | => And.make(ast1, ast2, token.Line, token.Column); 107 | 108 | public static ast mkOr(CommonToken token, ast ast1, ast ast2) 109 | => Or.make(ast1, ast2, token.Line, token.Column); 110 | 111 | public static ast mkPipeline(ast head, List tail) 112 | => Pipeline.make(head, tail.ToArray(), head.Lineno, head.Colno); 113 | 114 | public static DObj mkint(string s, int bit) 115 | { 116 | if (s.Length > 2) 117 | { 118 | return MK.Int(s.Substring(0, 2) switch 119 | { 120 | "0x" => Convert.ToInt64(s.Substring(2), 16), 121 | "0o" => Convert.ToInt64(s.Substring(2), 8), 122 | "0b" => Convert.ToInt64(s.Substring(2), 2), 123 | _ => long.Parse(s) 124 | }); 125 | } 126 | return MK.Int(long.Parse(s)); 127 | } 128 | 129 | public static DObj mkfloat(string s) => 130 | MK.Float(float.Parse(s)); 131 | 132 | public static DObj mkstr(string s) => 133 | MK.String(s); 134 | 135 | 136 | 137 | 138 | public static DObj mknone() => MK.None(); 139 | 140 | public static ast mkIfThen(CommonToken token, ast cond, ast then) 141 | { 142 | return IfThenElse.make( 143 | cond, then, 144 | CVal.make(MK.None(), token.Line, token.Column), 145 | token.Line, token.Column 146 | ); 147 | } 148 | 149 | 150 | public static ast mkRaise(CommonToken token, ast inner) 151 | { 152 | return Raise.make(inner, token.Line, token.Column); 153 | } 154 | 155 | public static ast mkBlock(CommonToken token, List suite) 156 | { 157 | return Block.make( 158 | suite.ToArray(), 159 | token.Line, 160 | token.Column 161 | ); 162 | } 163 | 164 | public static ast mkFunc(CommonToken token, string name, List args, List body) 165 | { 166 | return Function.make(name, args.ToArray(), 167 | mkBlock(token, body), token.Line, token.Column); 168 | } 169 | 170 | public static ast mkNestedIf(CommonToken token, List<(ast, ast)> elifs, ast orelse) 171 | { 172 | return NestedIf.make(elifs.ToArray(), orelse, token.Line, token.Column); 173 | } 174 | 175 | public static object mkop(CommonToken token, string opname) 176 | { 177 | return new Operator<(int lineno, int colno, string opname)>(opname, (token.Line, token.Column, opname)); 178 | } 179 | 180 | public static ast mkStoreMany(List<(ast, string)> lhs, ast value) 181 | { 182 | if (lhs.Count == 0) return value; 183 | return StoreMany.make(lhs.ToArray(), value, lhs[0].Item1.Lineno, lhs[0].Item1.Colno); 184 | } 185 | 186 | public static ast mkReturn(CommonToken token, ast v) 187 | { 188 | return Return.make(v, token.Line, token.Column); 189 | } 190 | 191 | public static ast mkContinue(CommonToken token) 192 | { 193 | return Continue.make(token.Line, token.Column); 194 | } 195 | 196 | public static ast mkBreak(CommonToken token) 197 | { 198 | return Break.make(token.Line, token.Column); 199 | } 200 | 201 | public static ast mkLoop(CommonToken token, ast body) 202 | { 203 | return Loop.make(body, token.Line, token.Column); 204 | } 205 | 206 | public static ast mkFor(CommonToken token, string target, ast iter, ast body) 207 | { 208 | return For.make(target, iter, body, token.Line, token.Column); 209 | } 210 | 211 | public static ast mkWorkflow(CommonToken token, string bindname, ast builder, List options) 212 | { 213 | return Workflow.make(bindname, builder, options.ToArray(), token.Line, token.Column); 214 | } 215 | 216 | public static ast mkOption(CommonToken token, string attr, List args) 217 | { 218 | return Option.make(attr, args.ToArray(), token.Line, token.Column); 219 | } 220 | 221 | public static ast mkWhile(CommonToken token, ast cond, ast body) 222 | { 223 | return While.make(cond, body, token.Line, token.Column); 224 | } 225 | 226 | // public static Option mkOption0(CommonToken token) 227 | // { 228 | // return (token.Line, token.Column, token.Text, new List{ 229 | // CVal.make(MK.Int(1), token.Line, token.Column) 230 | // }); 231 | // } 232 | 233 | public static ast mkDecl(CommonToken token, List names) 234 | { 235 | return Decl.make(names.ToArray(), token.Line, token.Column); 236 | } 237 | 238 | 239 | 240 | 241 | } 242 | 243 | } -------------------------------------------------------------------------------- /Diana.APIs/APIs.cs: -------------------------------------------------------------------------------- 1 | using Diana; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System; 5 | using System.Linq; 6 | using System.IO; 7 | 8 | #if !NUNITY 9 | using UnityEngine; 10 | #endif 11 | 12 | namespace Diana 13 | { 14 | 15 | using NameSpace = Dictionary; 16 | using ast = ImmediateAST; 17 | 18 | #if NUNITY 19 | public static class Debug 20 | { 21 | public static void Log(string s) 22 | { 23 | Console.WriteLine(s); 24 | } 25 | } 26 | #endif 27 | 28 | 29 | public static class ModularDianaExts 30 | { 31 | 32 | public static void SetValue(this NameSpace self, string v, DObj o) 33 | { 34 | self[v] = o; 35 | } 36 | public static void SetValue(this DModule self, string v, DObj o) 37 | { 38 | self.fields[v] = o; 39 | } 40 | 41 | public static DObj GetValue(this DModule self, string v) 42 | { 43 | return self.fields.TryGetValue(v, out var o) ? o : DNone.unique; 44 | } 45 | public static DObj GetValue(this NameSpace self, string v) 46 | { 47 | return self.TryGetValue(v, out var o) ? o : DNone.unique; 48 | } 49 | 50 | } 51 | 52 | public class ModularDiana 53 | { 54 | 55 | #if CONSOLE 56 | public static void Main(string[] args) 57 | { 58 | var imps = new ModularDiana(); 59 | args.ToList().ForEach(imps.LoadFromPath); 60 | main_calls.ForEach(runmain => runmain()); 61 | main_calls.Clear(); 62 | } 63 | #endif 64 | 65 | public string ApplicationPath; 66 | static List init_calls; 67 | public Dictionary ModuleCaches; 68 | 69 | public ModularDiana(string path = null) 70 | { 71 | ApplicationPath = path ?? Environment.CurrentDirectory; 72 | ModuleCaches = new Dictionary(); 73 | init_calls = new List(); 74 | } 75 | 76 | 77 | public void Exec(string path) 78 | { 79 | LoadFromPath(path); 80 | init_calls.ForEach(runinit => runinit()); 81 | init_calls.Clear(); 82 | } 83 | 84 | DModule ExecFromPath(string appPath, string path) 85 | { 86 | var apis = new DianaScriptAPIs(); 87 | var globals = apis.InitGlobals(); 88 | var mod = new DModule(appPath); 89 | var exported = mod.fields; 90 | mod.fields = globals; 91 | SetupNameSpace(mod, appPath); 92 | 93 | var ast = DianaScriptAPIs.Parse(path); 94 | var exec = DianaScriptAPIs.compileModule(ast, path); 95 | exec(globals); 96 | 97 | var init = globals.GetValue("init"); 98 | if (init is DStaticFunc f) 99 | { 100 | 101 | init_calls.Add(() => f.__call__()); 102 | } 103 | 104 | var exports = globals.GetValue("exports"); 105 | 106 | mod.fields = exported; 107 | if (exports is DDict dict) 108 | { 109 | foreach (var kv in dict.dict) 110 | { 111 | mod.fields[(string)(DString)kv.Key] = kv.Value; 112 | } 113 | } 114 | return mod; 115 | } 116 | 117 | void SetupNameSpace(DModule mod, string appPath) 118 | { 119 | mod.SetValue("__path__", MK.String(appPath)); 120 | mod.SetValue("module", mod); 121 | mod.SetValue("require", MK.Func1("require", x => Require(mod, (string)(DString)x))); 122 | ModuleCaches[appPath] = mod; 123 | } 124 | 125 | string AbsRelativePath(string relativeToAbs, string absPath) 126 | { 127 | return Path.GetFullPath(absPath, Path.GetDirectoryName(relativeToAbs)); 128 | } 129 | 130 | 131 | 132 | string resolveAbsPathFromCurrent(DModule mod, string relPath) 133 | { 134 | string currentAppPath = (string)(DString)mod.GetValue("__path__"); 135 | var currentAbsPath = Path.GetFullPath(currentAppPath, ApplicationPath); 136 | var absPath = AbsRelativePath(currentAbsPath, relPath); 137 | return absPath; 138 | } 139 | string getAppPath(string absPath) 140 | { 141 | return Path.GetRelativePath(ApplicationPath, absPath); 142 | } 143 | 144 | DModule ExecutePathWithNewModule(string absPath) 145 | { 146 | var appPath = 147 | absPath.EndsWith(".diana") 148 | ? getAppPath(absPath) 149 | : absPath + ".diana" 150 | ; 151 | if (ModuleCaches.TryGetValue(appPath, out var value)) 152 | return value; 153 | return ExecFromPath(appPath, absPath); 154 | } 155 | 156 | public void ForceCacheModule(string appPath, DModule mod) 157 | { 158 | ModuleCaches[appPath] = mod; 159 | } 160 | 161 | public void LoadFromPath(string relPath) 162 | { 163 | var absPath = Path.GetFullPath(relPath); 164 | ExecutePathWithNewModule(absPath); 165 | } 166 | 167 | DModule Require(DModule oldEngine, string relPath) 168 | { 169 | var absPath = 170 | relPath.EndsWith(".diana") 171 | ? resolveAbsPathFromCurrent(oldEngine, relPath) 172 | : relPath; 173 | return ExecutePathWithNewModule(absPath); 174 | } 175 | } 176 | 177 | public partial class DianaScriptAPIs 178 | { 179 | // Start is called before the first frame update 180 | 181 | #if NUNITY 182 | public static DObj time() 183 | { 184 | return MK.Int(System.DateTime.Now.Ticks); 185 | } 186 | #else 187 | public static DObj time() 188 | { 189 | return MK.Float(Time.realtimeSinceStartup); 190 | } 191 | #endif 192 | 193 | public static DObj classname(DObj o) 194 | { 195 | return MK.String(o.Classname); 196 | } 197 | 198 | public static DObj log(DObj[] args) 199 | { 200 | Debug.Log(String.Join(" ", args.Select(o => o.__str__()))); 201 | return DNone.unique; 202 | } 203 | 204 | public static DObj len(DObj arg) 205 | { 206 | return MK.Int(arg.__len__()); 207 | } 208 | 209 | public static DObj keys(DObj o) 210 | { 211 | if (o is DModule t) 212 | { 213 | if (t.fields == null) 214 | { 215 | return MK.Tuple(new DObj[0]); 216 | } 217 | return MK.Tuple(t.fields.Keys.Select(x => MK.String(x)).ToArray()); 218 | } 219 | if (o is DDict d) 220 | { 221 | return MK.Tuple(d.dict.Keys.ToArray()); 222 | } 223 | throw new TypeError($"cannot inspect keys from {o.Classname} object."); 224 | } 225 | 226 | public static DObj assert(DObj[] args) 227 | { 228 | switch (args.Length) 229 | { 230 | case 1: 231 | if (!args[0].__bool__()) 232 | throw new AssertionError(""); 233 | break; 234 | case 2: 235 | if (!args[0].__bool__()) 236 | throw new AssertionError(args[1].__str__()); 237 | break; 238 | default: 239 | throw new ArgumentException($"assert accepts only 2 arguments."); 240 | 241 | } 242 | return DNone.unique; 243 | } 244 | 245 | public Dictionary InitGlobals() 246 | { 247 | 248 | var ns = new Dictionary 249 | { 250 | {"log", MK.FuncN("log", log)}, 251 | {"typeof", MK.Func1("typeof", classname)}, 252 | {"time", MK.Func0("time", time)}, 253 | {"assert", MK.FuncN("assert", assert)}, 254 | {"keys", MK.Func1("keys", keys)}, 255 | {"len", MK.Func1("len", len)}, 256 | {DInt.module_instance.name, DInt.module_instance}, 257 | {DFloat.module_instance.name, DFloat.module_instance}, 258 | {DString.module_instance.name, DString.module_instance}, 259 | {DList.module_instance.name, DList.module_instance}, 260 | {DDict.module_instance.name, DDict.module_instance}, 261 | {DIterable.module_instance.name, DIterable.module_instance}, 262 | }; 263 | 264 | DObj isdefined(DObj s) 265 | { 266 | return MK.Int(ns.ContainsKey(((DString)s).value)); 267 | } 268 | 269 | ns.Add("isdefined", MK.Func1("isdefined", isdefined)); 270 | 271 | return ns; 272 | } 273 | 274 | public static Func compileModule(ast ast, string path, string name = null) 275 | { 276 | name = name ?? System.IO.Path.GetFileNameWithoutExtension(path); 277 | var ctx = MetaContext.Create(path); 278 | var cps = ast.jit_impl(ctx); 279 | var co = ctx.jitCode(ctx.currentPos, new string[0], name).Item2; 280 | return ns => ExecContext.ExecTopLevel(cps, ns, co); 281 | } 282 | 283 | } 284 | } -------------------------------------------------------------------------------- /Diana.Metagen/Metagen.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using Diana; 8 | #if !NUNITY 9 | using UnityEngine; 10 | #endif 11 | 12 | 13 | namespace Diana.Metagen 14 | { 15 | public class ClassAttribute : Attribute { } 16 | public class BindAttribute : Attribute { } 17 | public class ConverterAttribute : Attribute { } 18 | public class Metagen 19 | { 20 | const int BIT_GETTER = 0b01; 21 | const int BIT_SETTER = 0b10; 22 | Dictionary<(Type, Type), string> converters; 23 | Dictionary bindings; 24 | 25 | Assembly asm; 26 | string nameSpace; 27 | string outDir; 28 | public Metagen(Assembly asm, string nameSpace, string outDir) 29 | { 30 | this.asm = asm; 31 | this.nameSpace = nameSpace; 32 | this.outDir = 33 | #if NUNITY 34 | outDir; 35 | #else 36 | Path.Combine(Application.dataPath, outDir); 37 | #endif 38 | 39 | #if CODEGEN 40 | CheckCache(); 41 | #endif 42 | 43 | } 44 | 45 | 46 | #if CODEGEN 47 | string search_converter(Type from, Type to) 48 | { 49 | if (from == to) 50 | return ""; 51 | 52 | var key = (from, to); 53 | if (converters.TryGetValue(key, out var ret)) 54 | return ret; 55 | // warning 56 | return ""; 57 | } 58 | 59 | void CheckCache() 60 | { 61 | converters = new Dictionary<(Type, Type), string>(); 62 | bindings = new Dictionary(); 63 | 64 | 65 | var typename = String.Empty; 66 | 67 | foreach (var type in asm.GetClasses(nameSpace)) 68 | { 69 | if (type.GetCustomAttribute() != null) 70 | goto handle_converter; 71 | else if (type.GetCustomAttribute() != null) 72 | goto handle_diana_class; 73 | 74 | handle_converter: 75 | foreach (var mi in type.GetMethods(BindingFlags.Public | BindingFlags.Static)) 76 | { 77 | if (mi.GetCustomAttribute() == null || mi.GetParameters().Length != 1) 78 | continue; 79 | var pi = mi.GetParameters()[0]; 80 | var argtype = pi.ParameterType; 81 | var rettype = mi.ReturnType; 82 | converters[(argtype, rettype)] = string.Format( 83 | "{0}.{1}.{2}", 84 | mi.ReflectedType.Namespace, 85 | mi.ReflectedType.Name, 86 | mi.Name); 87 | } 88 | continue; 89 | 90 | handle_diana_class:; 91 | 92 | var class_bindings = new List<(string, int, Type)>(); 93 | foreach (var propInfo in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) 94 | { 95 | 96 | if (propInfo.GetCustomAttribute() != null) 97 | { 98 | var propType = propInfo.PropertyType; 99 | var bit = 0; 100 | if(propInfo.CanRead) 101 | bit |= BIT_GETTER; 102 | if(propInfo.CanWrite) 103 | bit |= BIT_SETTER; 104 | class_bindings.Add((propInfo.Name, bit, propType)); 105 | } 106 | } 107 | bindings[type] = class_bindings.ToArray(); 108 | continue; 109 | } 110 | 111 | var bindings_ = asm.GetType($"{nameSpace}.MetagenMeta")?.GetStaticField>("bindings"); 112 | 113 | 114 | if (bindings_ != null && bindings_.SequenceEqual(bindings)) 115 | return; 116 | // do code generation 117 | 118 | GenerateMeta(); 119 | GenerateBinding(); 120 | } 121 | 122 | 123 | void GenerateBinding() 124 | { 125 | foreach(var (cls, pairs) in bindings) 126 | { 127 | GenerateBindingForClass(cls, pairs); 128 | } 129 | } 130 | void GenerateBindingForClass(Type cls, (string, int, Type)[] pairs) 131 | { 132 | 133 | var srcPath = Path.Combine(outDir, $"{cls.Name}.Binding.cs"); 134 | var required_namespaces = new HashSet { "System", "System.Collections.Generic" }; 135 | string err_msg; 136 | var sb = new StringBuilder(); 137 | 138 | sb.AddLines($"namespace {nameSpace} {{"); 139 | sb.AddLines($"public partial class {cls.Name} {{"); 140 | 141 | sb.AddLines( 142 | $" public DObj __get__(DObj __attrobj)", 143 | @" {", 144 | @" var __attr = (string) (DString) __attrobj;", 145 | @" switch(__attr){"); 146 | foreach(var (fieldname, bit, fieldtype) in pairs) 147 | { 148 | if ((bit & BIT_GETTER) == 0) 149 | continue; 150 | var conv = search_converter(fieldtype, typeof(DObj)); 151 | sb.AddLines( 152 | $" case \"{fieldname}\":", 153 | $" return {conv}({fieldname});"); 154 | 155 | } 156 | 157 | err_msg = $"cannot get attribute ({{__attr}}) from {cls.Name}"; 158 | sb.AddLines( 159 | $" default:", 160 | $" throw new AttributeError($\"{err_msg}\");"); 161 | 162 | sb.AddLines( 163 | @" }", 164 | @" }" 165 | 166 | ); 167 | 168 | 169 | sb.AddLines( 170 | $" public void __set__(DObj __attrobj, DObj __value)", 171 | @" {", 172 | @" var __attr = (string) (DString) __attrobj;", 173 | @" switch(__attr){"); 174 | foreach(var (fieldname, bit, fieldtype) in pairs) 175 | { 176 | if ((bit & BIT_SETTER) == 0) 177 | continue; 178 | var conv = search_converter(typeof(DObj), fieldtype); 179 | sb.AddLines( 180 | $" case \"{fieldname}\":", 181 | $" {fieldname} = {conv}(__value);", 182 | @" return;"); 183 | } 184 | err_msg = $"cannot set attribute ({{__attr}}) from {cls.Name}"; 185 | sb.AddLines( 186 | $" default:", 187 | $" throw new AttributeError($\"{err_msg}\");"); 188 | 189 | sb.AddLines( 190 | @" }", 191 | @" }" 192 | 193 | ); 194 | sb.AddLines("}"); // class 195 | sb.AddLines("}"); // namespace 196 | 197 | File.WriteAllText( 198 | srcPath, 199 | String.Join("\n", required_namespaces.ToList().OrderBy(x => x).Select(x => $"using {x};")) 200 | + "\n" 201 | + sb.ToString()); 202 | } 203 | 204 | void GenerateMeta() 205 | { 206 | var srcPath = Path.Combine(outDir, "MetagenMeta.cs"); 207 | var sb = new StringBuilder(); 208 | 209 | var required_namespaces = new HashSet { "System", "System.Collections.Generic" }; 210 | 211 | sb.AddLines($"namespace {nameSpace} {{"); 212 | 213 | sb.AddLines("public class MetagenMeta {"); 214 | 215 | // sb.AddLines("public Dictionary<(Type, Type), string> converters = new Dictionary<(Type, Type), string> {"); 216 | // foreach(var ((t1, t2), method_name) in converters) 217 | // { 218 | // required_namespaces.Add(t1.Namespace); 219 | // required_namespaces.Add(t2.Namespace); 220 | // sb.AddLines( 221 | // $" {{(typeof({t1.GetQualifiedName()}), typeof({t2.GetQualifiedName()})), \"{method_name}\"}}," 222 | // ); 223 | // } 224 | // sb.AddLines("};"); 225 | 226 | 227 | sb.AddLines("public Dictionary bindings = new Dictionary {"); 228 | foreach(var (cls, pairs) in bindings) 229 | { 230 | required_namespaces.Add(cls.Namespace); 231 | sb.AddLines($" {{typeof({cls.GetQualifiedName()}), new (string, int, Type)[]{{"); 232 | foreach(var (fieldname, bit, fieldtype) in pairs) 233 | { 234 | required_namespaces.Add(fieldtype.Namespace); 235 | sb.AddLines($" (\"{fieldname}\", {bit}, typeof({fieldtype.GetQualifiedName()})),"); 236 | } 237 | sb.AddLines(" }},"); 238 | } 239 | sb.AddLines("};"); 240 | 241 | 242 | sb.AddLines("}"); // end class 243 | sb.AddLines("}"); // end namespace 244 | 245 | File.WriteAllText( 246 | srcPath, 247 | String.Join("\n", required_namespaces.ToList().OrderBy(x => x).Select(x => $"using {x};")) 248 | + "\n" 249 | + sb.ToString()); 250 | } 251 | #endif 252 | } 253 | 254 | static class Helper 255 | { 256 | public static void AddLines(this StringBuilder self, params string[] args) 257 | { 258 | foreach(var arg in args) 259 | { 260 | self.Append(arg); 261 | self.Append("\n"); 262 | } 263 | } 264 | public static T GetStaticField(this Type self, string attr) where T : class 265 | { 266 | var o = self.GetField(attr, BindingFlags.Public | BindingFlags.Static); 267 | if (o == null) 268 | return null; 269 | return o.GetValue(null) as T; 270 | } 271 | 272 | public static string GetQualifiedName(this Type self) 273 | { 274 | return string.Format("{0}.{1}", self.Namespace, self.Name); 275 | } 276 | 277 | 278 | public static IEnumerable GetClasses(this Assembly asm, string nameSpace) 279 | { 280 | return asm.GetTypes() 281 | .Where(type => type.Namespace == nameSpace); 282 | } 283 | } 284 | 285 | } -------------------------------------------------------------------------------- /Diana.Generated/Methods.DDict.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | namespace Diana 4 | { 5 | public partial class DDict 6 | { 7 | public string Classname => "Dict"; 8 | public static DModule module_instance {get; private set;} 9 | public static DObj bind_remove(DObj[] _args) // bind method 10 | { 11 | var nargs = _args.Length; 12 | if (nargs != 2) 13 | throw new ArgumentException($"calling Dict.remove; needs at least (2) arguments, got {nargs}."); 14 | var _arg0 = MK.unbox(THint>.val, _args[0]); 15 | var _arg1 = MK.unbox(THint.val, _args[1]); 16 | { 17 | _arg0.Remove(_arg1); 18 | return MK.None(); 19 | } 20 | throw new ArgumentException($"call Dict.remove; needs at most (2) arguments, got {nargs}."); 21 | } 22 | public static DObj bind_clear(DObj[] _args) // bind method 23 | { 24 | var nargs = _args.Length; 25 | if (nargs != 1) 26 | throw new ArgumentException($"calling Dict.clear; needs at least (1) arguments, got {nargs}."); 27 | var _arg0 = MK.unbox(THint>.val, _args[0]); 28 | { 29 | _arg0.Clear(); 30 | return MK.None(); 31 | } 32 | throw new ArgumentException($"call Dict.clear; needs at most (1) arguments, got {nargs}."); 33 | } 34 | public static DObj bind_len(DObj[] _args) // bind `this` prop 35 | { 36 | var nargs = _args.Length; 37 | if (nargs != 1) 38 | throw new ArgumentException($"accessing Dict.len; needs only 1 argument, got {nargs}."); 39 | var arg = _args[0]; 40 | var ret = MK.unbox(THint>.val, arg).Count; 41 | return MK.create(ret); 42 | } 43 | public static DObj bind_contains(DObj[] _args) // bind method 44 | { 45 | var nargs = _args.Length; 46 | if (nargs != 2) 47 | throw new ArgumentException($"calling Dict.contains; needs at least (2) arguments, got {nargs}."); 48 | var _arg0 = MK.unbox(THint>.val, _args[0]); 49 | var _arg1 = MK.unbox(THint.val, _args[1]); 50 | { 51 | _arg0.ContainsKey(_arg1); 52 | return MK.None(); 53 | } 54 | throw new ArgumentException($"call Dict.contains; needs at most (2) arguments, got {nargs}."); 55 | } 56 | public static DObj bind_search(DObj[] _args) // bind method 57 | { 58 | var nargs = _args.Length; 59 | if (nargs != 3) 60 | throw new ArgumentException($"calling Dict.search; needs at least (3) arguments, got {nargs}."); 61 | var _arg0 = MK.unbox(THint>.val, _args[0]); 62 | var _arg1 = MK.unbox(THint.val, _args[1]); 63 | var _out_2 = MK.unbox(THint.val, _args[2]); 64 | var _arg2 = MK.unbox(THint.val, _out_2.GetContents()); 65 | { 66 | var _return = _arg0.TryGetValue(_arg1,out _arg2); 67 | _out_2.SetContents(MK.cast(THint.val, _arg2)); 68 | return MK.create(_return); 69 | } 70 | throw new ArgumentException($"call Dict.search; needs at most (3) arguments, got {nargs}."); 71 | } 72 | public static DObj bind_subtract(DObj[] _args) // bind method 73 | { 74 | var nargs = _args.Length; 75 | if (nargs != 2) 76 | throw new ArgumentException($"calling Dict.subtract; needs at least (2) arguments, got {nargs}."); 77 | var _arg0 = MK.unbox(THint>.val, _args[0]); 78 | var _arg1 = MK.unbox(THint.val, _args[1]); 79 | { 80 | var _return = CollectionExts.DifferenceDObj(_arg0,_arg1); 81 | return MK.create(_return); 82 | } 83 | throw new ArgumentException($"call Dict.subtract; needs at most (2) arguments, got {nargs}."); 84 | } 85 | public static DObj bind_union(DObj[] _args) // bind method 86 | { 87 | var nargs = _args.Length; 88 | if (nargs != 2) 89 | throw new ArgumentException($"calling Dict.union; needs at least (2) arguments, got {nargs}."); 90 | var _arg0 = MK.unbox(THint>.val, _args[0]); 91 | var _arg1 = MK.unbox(THint>.val, _args[1]); 92 | { 93 | var _return = CollectionExts.Union(_arg0,_arg1); 94 | return MK.create(_return); 95 | } 96 | throw new ArgumentException($"call Dict.union; needs at most (2) arguments, got {nargs}."); 97 | } 98 | public static DObj bind_union_dict(DObj[] _args) // bind method 99 | { 100 | var nargs = _args.Length; 101 | if (nargs != 2) 102 | throw new ArgumentException($"calling Dict.union_dict; needs at least (2) arguments, got {nargs}."); 103 | var _arg0 = MK.unbox(THint>.val, _args[0]); 104 | var _arg1 = MK.unbox(THint>.val, _args[1]); 105 | { 106 | var _return = CollectionExts.UnionDict(_arg0,_arg1); 107 | return MK.create(_return); 108 | } 109 | throw new ArgumentException($"call Dict.union_dict; needs at most (2) arguments, got {nargs}."); 110 | } 111 | public static DObj bind_intersect(DObj[] _args) // bind method 112 | { 113 | var nargs = _args.Length; 114 | if (nargs != 2) 115 | throw new ArgumentException($"calling Dict.intersect; needs at least (2) arguments, got {nargs}."); 116 | var _arg0 = MK.unbox(THint>.val, _args[0]); 117 | var _arg1 = MK.unbox(THint>.val, _args[1]); 118 | { 119 | var _return = CollectionExts.Intersect(_arg0,_arg1); 120 | return MK.create(_return); 121 | } 122 | throw new ArgumentException($"call Dict.intersect; needs at most (2) arguments, got {nargs}."); 123 | } 124 | public static DObj bind_add(DObj[] _args) // bind method 125 | { 126 | var nargs = _args.Length; 127 | if (nargs != 2) 128 | throw new ArgumentException($"calling Dict.add; needs at least (2) arguments, got {nargs}."); 129 | var _arg0 = MK.unbox(THint>.val, _args[0]); 130 | var _arg1 = MK.unbox(THint.val, _args[1]); 131 | { 132 | CollectionExts.AddAsSet(_arg0,_arg1); 133 | return MK.None(); 134 | } 135 | throw new ArgumentException($"call Dict.add; needs at most (2) arguments, got {nargs}."); 136 | } 137 | public static DObj bind_quotient(DObj[] _args) // bind method 138 | { 139 | var nargs = _args.Length; 140 | if (nargs != 2) 141 | throw new ArgumentException($"calling Dict.quotient; needs at least (2) arguments, got {nargs}."); 142 | var _arg0 = MK.unbox(THint.val, _args[0]); 143 | var _arg1 = MK.unbox(THint.val, _args[1]); 144 | { 145 | var _return = _arg0.__truediv__(_arg1); 146 | return MK.create(_return); 147 | } 148 | throw new ArgumentException($"call Dict.quotient; needs at most (2) arguments, got {nargs}."); 149 | } 150 | public static DObj bind_items(DObj[] _args) // bind method 151 | { 152 | var nargs = _args.Length; 153 | if (nargs != 1) 154 | throw new ArgumentException($"calling Dict.items; needs at least (1) arguments, got {nargs}."); 155 | var _arg0 = MK.unbox(THint>.val, _args[0]); 156 | { 157 | var _return = CollectionExts.ObjectPairs(_arg0); 158 | return MK.create(_return); 159 | } 160 | throw new ArgumentException($"call Dict.items; needs at most (1) arguments, got {nargs}."); 161 | } 162 | public static DObj bind_forkey(DObj[] _args) // bind method 163 | { 164 | var nargs = _args.Length; 165 | if (nargs != 2) 166 | throw new ArgumentException($"calling Dict.forkey; needs at least (2) arguments, got {nargs}."); 167 | var _arg0 = MK.unbox(THint>.val, _args[0]); 168 | var _arg1 = MK.unbox(THint.val, _args[1]); 169 | { 170 | _arg0.ForEachIndex_(_arg1); 171 | return MK.None(); 172 | } 173 | throw new ArgumentException($"call Dict.forkey; needs at most (2) arguments, got {nargs}."); 174 | } 175 | public static DObj bind_update(DObj[] _args) // bind method 176 | { 177 | var nargs = _args.Length; 178 | if (nargs != 2) 179 | throw new ArgumentException($"calling Dict.update; needs at least (2) arguments, got {nargs}."); 180 | var _arg0 = MK.unbox(THint>.val, _args[0]); 181 | var _arg1 = MK.unbox(THint>.val, _args[1]); 182 | { 183 | _arg0.Merge(_arg1); 184 | return MK.None(); 185 | } 186 | throw new ArgumentException($"call Dict.update; needs at most (2) arguments, got {nargs}."); 187 | } 188 | public static DObj bind_of(DObj[] _args) // bind method 189 | { 190 | var nargs = _args.Length; 191 | if (nargs != 1) 192 | throw new ArgumentException($"calling Dict.of; needs at least (1) arguments, got {nargs}."); 193 | var _arg0 = MK.unbox(THint>.val, _args[0]); 194 | { 195 | var _return = CollectionExts.dictOf(_arg0); 196 | return MK.create(_return); 197 | } 198 | throw new ArgumentException($"call Dict.of; needs at most (1) arguments, got {nargs}."); 199 | } 200 | public static DObj bind_setOf(DObj[] _args) // bind method 201 | { 202 | var nargs = _args.Length; 203 | if (nargs != 1) 204 | throw new ArgumentException($"calling Dict.setOf; needs at least (1) arguments, got {nargs}."); 205 | var _arg0 = MK.unbox(THint>.val, _args[0]); 206 | { 207 | var _return = CollectionExts.setOf(_arg0); 208 | return MK.create(_return); 209 | } 210 | throw new ArgumentException($"call Dict.setOf; needs at most (1) arguments, got {nargs}."); 211 | } 212 | public static DObj bind_copy(DObj[] _args) // bind method 213 | { 214 | var nargs = _args.Length; 215 | if (nargs != 1) 216 | throw new ArgumentException($"calling Dict.copy; needs at least (1) arguments, got {nargs}."); 217 | var _arg0 = MK.unbox(THint>.val, _args[0]); 218 | { 219 | var _return = _arg0.ShallowCopy(); 220 | return MK.create(_return); 221 | } 222 | throw new ArgumentException($"call Dict.copy; needs at most (1) arguments, got {nargs}."); 223 | } 224 | static DDict() 225 | { 226 | module_instance = new DModule("Dict"); 227 | module_instance.fields.Add("remove", MK.FuncN("Dict.remove", bind_remove)); 228 | module_instance.fields.Add("clear", MK.FuncN("Dict.clear", bind_clear)); 229 | module_instance.fields.Add("len", MK.FuncN("Dict.len", bind_len)); 230 | module_instance.fields.Add("contains", MK.FuncN("Dict.contains", bind_contains)); 231 | module_instance.fields.Add("search", MK.FuncN("Dict.search", bind_search)); 232 | module_instance.fields.Add("subtract", MK.FuncN("Dict.subtract", bind_subtract)); 233 | module_instance.fields.Add("union", MK.FuncN("Dict.union", bind_union)); 234 | module_instance.fields.Add("union_dict", MK.FuncN("Dict.union_dict", bind_union_dict)); 235 | module_instance.fields.Add("intersect", MK.FuncN("Dict.intersect", bind_intersect)); 236 | module_instance.fields.Add("add", MK.FuncN("Dict.add", bind_add)); 237 | module_instance.fields.Add("quotient", MK.FuncN("Dict.quotient", bind_quotient)); 238 | module_instance.fields.Add("items", MK.FuncN("Dict.items", bind_items)); 239 | module_instance.fields.Add("forkey", MK.FuncN("Dict.forkey", bind_forkey)); 240 | module_instance.fields.Add("update", MK.FuncN("Dict.update", bind_update)); 241 | module_instance.fields.Add("of", MK.FuncN("Dict.of", bind_of)); 242 | module_instance.fields.Add("setOf", MK.FuncN("Dict.setOf", bind_setOf)); 243 | module_instance.fields.Add("copy", MK.FuncN("Dict.copy", bind_copy)); 244 | } 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /Diana.Generated/Methods.DString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | namespace Diana 4 | { 5 | public partial class DString 6 | { 7 | public string Classname => "Str"; 8 | public static DModule module_instance {get; private set;} 9 | public static DObj bind_join(DObj[] _args) // bind method 10 | { 11 | var nargs = _args.Length; 12 | if (nargs != 2) 13 | throw new ArgumentException($"calling Str.join; needs at least (2) arguments, got {nargs}."); 14 | var _arg0 = MK.unbox(THint.val, _args[0]); 15 | var _arg1 = MK.cast(THint>.val, MK.unbox(THint.val, _args[1])); 16 | { 17 | var _return = String.Join(_arg0,_arg1); 18 | return MK.create(_return); 19 | } 20 | throw new ArgumentException($"call Str.join; needs at most (2) arguments, got {nargs}."); 21 | } 22 | public static DObj bind_concat(DObj[] _args) // bind method 23 | { 24 | var nargs = _args.Length; 25 | if (nargs != 1) 26 | throw new ArgumentException($"calling Str.concat; needs at least (1) arguments, got {nargs}."); 27 | var _arg0 = MK.cast(THint>.val, MK.unbox(THint.val, _args[0])); 28 | { 29 | var _return = String.Concat(_arg0); 30 | return MK.create(_return); 31 | } 32 | throw new ArgumentException($"call Str.concat; needs at most (1) arguments, got {nargs}."); 33 | } 34 | public static DObj bind_endswith(DObj[] _args) // bind method 35 | { 36 | var nargs = _args.Length; 37 | if (nargs != 2) 38 | throw new ArgumentException($"calling Str.endswith; needs at least (2) arguments, got {nargs}."); 39 | var _arg0 = MK.unbox(THint.val, _args[0]); 40 | var _arg1 = MK.unbox(THint.val, _args[1]); 41 | { 42 | var _return = _arg0.EndsWith(_arg1); 43 | return MK.create(_return); 44 | } 45 | throw new ArgumentException($"call Str.endswith; needs at most (2) arguments, got {nargs}."); 46 | } 47 | public static DObj bind_startswith(DObj[] _args) // bind method 48 | { 49 | var nargs = _args.Length; 50 | if (nargs != 2) 51 | throw new ArgumentException($"calling Str.startswith; needs at least (2) arguments, got {nargs}."); 52 | var _arg0 = MK.unbox(THint.val, _args[0]); 53 | var _arg1 = MK.unbox(THint.val, _args[1]); 54 | { 55 | var _return = _arg0.StartsWith(_arg1); 56 | return MK.create(_return); 57 | } 58 | throw new ArgumentException($"call Str.startswith; needs at most (2) arguments, got {nargs}."); 59 | } 60 | public static DObj bind_len(DObj[] _args) // bind `this` prop 61 | { 62 | var nargs = _args.Length; 63 | if (nargs != 1) 64 | throw new ArgumentException($"accessing Str.len; needs only 1 argument, got {nargs}."); 65 | var arg = _args[0]; 66 | var ret = MK.unbox(THint.val, arg).Length; 67 | return MK.create(ret); 68 | } 69 | public static DObj bind_strip(DObj[] _args) // bind method 70 | { 71 | var nargs = _args.Length; 72 | if (nargs < 1) 73 | throw new ArgumentException($"calling Str.strip; needs at least (1,2) arguments, got {nargs}."); 74 | var _arg0 = MK.unbox(THint.val, _args[0]); 75 | if (nargs == 1) 76 | { 77 | var _return = _arg0.Trim(); 78 | return MK.create(_return); 79 | } 80 | var _arg1 = MK.cast(THint.val, MK.unbox(THint.val, _args[1])); 81 | { 82 | var _return = _arg0.Trim(_arg1); 83 | return MK.create(_return); 84 | } 85 | throw new ArgumentException($"call Str.strip; needs at most (2) arguments, got {nargs}."); 86 | } 87 | public static DObj bind_rstrip(DObj[] _args) // bind method 88 | { 89 | var nargs = _args.Length; 90 | if (nargs < 1) 91 | throw new ArgumentException($"calling Str.rstrip; needs at least (1,2) arguments, got {nargs}."); 92 | var _arg0 = MK.unbox(THint.val, _args[0]); 93 | if (nargs == 1) 94 | { 95 | var _return = _arg0.TrimEnd(); 96 | return MK.create(_return); 97 | } 98 | var _arg1 = MK.cast(THint.val, MK.unbox(THint.val, _args[1])); 99 | { 100 | var _return = _arg0.TrimEnd(_arg1); 101 | return MK.create(_return); 102 | } 103 | throw new ArgumentException($"call Str.rstrip; needs at most (2) arguments, got {nargs}."); 104 | } 105 | public static DObj bind_lstrip(DObj[] _args) // bind method 106 | { 107 | var nargs = _args.Length; 108 | if (nargs < 1) 109 | throw new ArgumentException($"calling Str.lstrip; needs at least (1,2) arguments, got {nargs}."); 110 | var _arg0 = MK.unbox(THint.val, _args[0]); 111 | if (nargs == 1) 112 | { 113 | var _return = _arg0.TrimStart(); 114 | return MK.create(_return); 115 | } 116 | var _arg1 = MK.cast(THint.val, MK.unbox(THint.val, _args[1])); 117 | { 118 | var _return = _arg0.TrimStart(_arg1); 119 | return MK.create(_return); 120 | } 121 | throw new ArgumentException($"call Str.lstrip; needs at most (2) arguments, got {nargs}."); 122 | } 123 | public static DObj bind_lower(DObj[] _args) // bind method 124 | { 125 | var nargs = _args.Length; 126 | if (nargs != 1) 127 | throw new ArgumentException($"calling Str.lower; needs at least (1) arguments, got {nargs}."); 128 | var _arg0 = MK.unbox(THint.val, _args[0]); 129 | { 130 | var _return = _arg0.ToLowerInvariant(); 131 | return MK.create(_return); 132 | } 133 | throw new ArgumentException($"call Str.lower; needs at most (1) arguments, got {nargs}."); 134 | } 135 | public static DObj bind_upper(DObj[] _args) // bind method 136 | { 137 | var nargs = _args.Length; 138 | if (nargs != 1) 139 | throw new ArgumentException($"calling Str.upper; needs at least (1) arguments, got {nargs}."); 140 | var _arg0 = MK.unbox(THint.val, _args[0]); 141 | { 142 | var _return = _arg0.ToUpperInvariant(); 143 | return MK.create(_return); 144 | } 145 | throw new ArgumentException($"call Str.upper; needs at most (1) arguments, got {nargs}."); 146 | } 147 | public static DObj bind_contains(DObj[] _args) // bind method 148 | { 149 | var nargs = _args.Length; 150 | if (nargs != 2) 151 | throw new ArgumentException($"calling Str.contains; needs at least (2) arguments, got {nargs}."); 152 | var _arg0 = MK.unbox(THint.val, _args[0]); 153 | var _arg1 = MK.unbox(THint.val, _args[1]); 154 | { 155 | var _return = _arg0.Contains(_arg1); 156 | return MK.create(_return); 157 | } 158 | throw new ArgumentException($"call Str.contains; needs at most (2) arguments, got {nargs}."); 159 | } 160 | public static DObj bind_format(DObj[] _args) // bind method 161 | { 162 | var nargs = _args.Length; 163 | if (nargs < 1) 164 | throw new ArgumentException($"calling Str.format; needs at least >= (1) arguments, got {nargs}."); 165 | var _arg0 = MK.unbox(THint.val, _args[0]); 166 | if (nargs == 1) 167 | { 168 | var _return = String.Format(_arg0); 169 | return MK.create(_return); 170 | } 171 | var _arg1 = new Object[nargs - 1]; 172 | for(var _i = 1; _i < nargs; _i++) 173 | _arg1[_i - 1] = _args[_i]; 174 | { 175 | var _return = String.Format(_arg0,_arg1); 176 | return MK.create(_return); 177 | } 178 | } 179 | public static DObj bind_substr(DObj[] _args) // bind method 180 | { 181 | var nargs = _args.Length; 182 | if (nargs < 2) 183 | throw new ArgumentException($"calling Str.substr; needs at least (2,3) arguments, got {nargs}."); 184 | var _arg0 = MK.unbox(THint.val, _args[0]); 185 | var _arg1 = MK.unbox(THint.val, _args[1]); 186 | if (nargs == 2) 187 | { 188 | var _return = _arg0.Substring(_arg1); 189 | return MK.create(_return); 190 | } 191 | var _arg2 = MK.unbox(THint.val, _args[2]); 192 | { 193 | var _return = _arg0.Substring(_arg1,_arg2); 194 | return MK.create(_return); 195 | } 196 | throw new ArgumentException($"call Str.substr; needs at most (3) arguments, got {nargs}."); 197 | } 198 | public static DObj bind_insert(DObj[] _args) // bind method 199 | { 200 | var nargs = _args.Length; 201 | if (nargs != 3) 202 | throw new ArgumentException($"calling Str.insert; needs at least (3) arguments, got {nargs}."); 203 | var _arg0 = MK.unbox(THint.val, _args[0]); 204 | var _arg1 = MK.unbox(THint.val, _args[1]); 205 | var _arg2 = MK.unbox(THint.val, _args[2]); 206 | { 207 | var _return = _arg0.Insert(_arg1,_arg2); 208 | return MK.create(_return); 209 | } 210 | throw new ArgumentException($"call Str.insert; needs at most (3) arguments, got {nargs}."); 211 | } 212 | public static DObj bind_remove_at(DObj[] _args) // bind method 213 | { 214 | var nargs = _args.Length; 215 | if (nargs < 2) 216 | throw new ArgumentException($"calling Str.remove_at; needs at least (2,3) arguments, got {nargs}."); 217 | var _arg0 = MK.unbox(THint.val, _args[0]); 218 | var _arg1 = MK.unbox(THint.val, _args[1]); 219 | if (nargs == 2) 220 | { 221 | var _return = _arg0.Remove(_arg1); 222 | return MK.create(_return); 223 | } 224 | var _arg2 = MK.unbox(THint.val, _args[2]); 225 | { 226 | var _return = _arg0.Remove(_arg1,_arg2); 227 | return MK.create(_return); 228 | } 229 | throw new ArgumentException($"call Str.remove_at; needs at most (3) arguments, got {nargs}."); 230 | } 231 | public static DObj bind_index(DObj[] _args) // bind method 232 | { 233 | var nargs = _args.Length; 234 | if (nargs < 2) 235 | throw new ArgumentException($"calling Str.index; needs at least (2,3,4) arguments, got {nargs}."); 236 | var _arg0 = MK.unbox(THint.val, _args[0]); 237 | var _arg1 = MK.unbox(THint.val, _args[1]); 238 | if (nargs == 2) 239 | { 240 | var _return = _arg0.IndexOf(_arg1); 241 | return MK.create(_return); 242 | } 243 | var _arg2 = MK.unbox(THint.val, _args[2]); 244 | if (nargs == 3) 245 | { 246 | var _return = _arg0.IndexOf(_arg1,_arg2); 247 | return MK.create(_return); 248 | } 249 | var _arg3 = MK.unbox(THint.val, _args[3]); 250 | { 251 | var _return = _arg0.IndexOf(_arg1,_arg2,_arg3); 252 | return MK.create(_return); 253 | } 254 | throw new ArgumentException($"call Str.index; needs at most (4) arguments, got {nargs}."); 255 | } 256 | public static DObj bind_of(DObj[] _args) // bind method 257 | { 258 | var nargs = _args.Length; 259 | if (nargs != 1) 260 | throw new ArgumentException($"calling Str.of; needs at least (1) arguments, got {nargs}."); 261 | var _arg0 = MK.unbox(THint.val, _args[0]); 262 | { 263 | var _return = TypeConversion.toStr(_arg0); 264 | return MK.create(_return); 265 | } 266 | throw new ArgumentException($"call Str.of; needs at most (1) arguments, got {nargs}."); 267 | } 268 | static DString() 269 | { 270 | module_instance = new DModule("Str"); 271 | module_instance.fields.Add("join", MK.FuncN("Str.join", bind_join)); 272 | module_instance.fields.Add("concat", MK.FuncN("Str.concat", bind_concat)); 273 | module_instance.fields.Add("endswith", MK.FuncN("Str.endswith", bind_endswith)); 274 | module_instance.fields.Add("startswith", MK.FuncN("Str.startswith", bind_startswith)); 275 | module_instance.fields.Add("len", MK.FuncN("Str.len", bind_len)); 276 | module_instance.fields.Add("strip", MK.FuncN("Str.strip", bind_strip)); 277 | module_instance.fields.Add("rstrip", MK.FuncN("Str.rstrip", bind_rstrip)); 278 | module_instance.fields.Add("lstrip", MK.FuncN("Str.lstrip", bind_lstrip)); 279 | module_instance.fields.Add("lower", MK.FuncN("Str.lower", bind_lower)); 280 | module_instance.fields.Add("upper", MK.FuncN("Str.upper", bind_upper)); 281 | module_instance.fields.Add("contains", MK.FuncN("Str.contains", bind_contains)); 282 | module_instance.fields.Add("format", MK.FuncN("Str.format", bind_format)); 283 | module_instance.fields.Add("substr", MK.FuncN("Str.substr", bind_substr)); 284 | module_instance.fields.Add("insert", MK.FuncN("Str.insert", bind_insert)); 285 | module_instance.fields.Add("remove_at", MK.FuncN("Str.remove_at", bind_remove_at)); 286 | module_instance.fields.Add("index", MK.FuncN("Str.index", bind_index)); 287 | module_instance.fields.Add("of", MK.FuncN("Str.of", bind_of)); 288 | } 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /Diana/NumMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using int_t = System.Int64; 4 | using uint_t = System.UInt64; 5 | 6 | namespace Diana 7 | { 8 | #if NUNITY 9 | using static System.MathF; 10 | 11 | #else 12 | using static UnityEngine.Mathf; 13 | #endif 14 | public static class NumberMethods 15 | { 16 | static int_t s_intmod(int_t a, int_t b) 17 | { 18 | int_t r = a % b; 19 | return r < 0 ? r + b : r; 20 | } 21 | 22 | static float s_floatmod(float a, float b) 23 | { 24 | float r = a % b; 25 | return r < 0 ? r + b : r; 26 | } 27 | 28 | 29 | public static Exception unsupported_ops(DObj lhs, string op, DObj rhs) => 30 | new InvalidOperationException($"'unsupported operation: '{lhs.Classname}' {op} '{rhs.Classname}'."); 31 | 32 | [MethodImpl(MethodImplOptionsCompat.AggressiveOptimization | MethodImplOptionsCompat.AggressiveInlining)] 33 | public static DObj int_t_add(DInt self, DObj other) 34 | { 35 | switch (other) 36 | { 37 | case DInt v: return MK.Int(self.value + v.value); 38 | case DFloat v: return MK.Float(self.value + v.value); 39 | default: 40 | throw unsupported_ops(self, "+", other); 41 | } 42 | } 43 | 44 | public static DObj float_add(DFloat self, DObj other) 45 | { 46 | switch (other) 47 | { 48 | case DFloat v: return MK.Float(self.value + v.value); 49 | case DInt v: return MK.Float(self.value + v.value); 50 | default: 51 | throw unsupported_ops(self, "+", other); 52 | } 53 | } 54 | 55 | [MethodImpl(MethodImplOptionsCompat.AggressiveOptimization | MethodImplOptionsCompat.AggressiveInlining)] 56 | public static DObj int_t_sub(DInt self, DObj other) 57 | { 58 | switch (other) 59 | { 60 | case DFloat v: return MK.Float(self.value - v.value); 61 | case DInt v: return MK.Int(self.value - v.value); 62 | default: 63 | throw unsupported_ops(self, "-", other); 64 | } 65 | } 66 | 67 | public static DObj float_sub(DFloat self, DObj other) 68 | { 69 | switch (other) 70 | { 71 | case DFloat v: return MK.Float(self.value - v.value); 72 | case DInt v: return MK.Float(self.value - v.value); 73 | default: 74 | throw unsupported_ops(self, "-", other); 75 | } 76 | } 77 | 78 | public static DObj int_t_mul(DInt self, DObj other) 79 | { 80 | switch (other) 81 | { 82 | case DFloat v: return MK.Float(self.value * v.value); 83 | case DInt v: return MK.Int(self.value * v.value); 84 | default: 85 | throw unsupported_ops(self, "*", other); 86 | } 87 | } 88 | 89 | public static DObj float_mul(DFloat self, DObj other) 90 | { 91 | switch (other) 92 | { 93 | case DFloat v: return MK.Float(self.value * v.value); 94 | case DInt v: return MK.Float(self.value * v.value); 95 | default: 96 | throw unsupported_ops(self, "*", other); 97 | } 98 | } 99 | 100 | public static DObj int_t_floordiv(DInt self, DObj other) 101 | { 102 | switch (other) 103 | { 104 | case DFloat v: return MK.Int((int_t) (self.value / v.value)); 105 | case DInt v: return MK.Int(self.value / v.value); 106 | default: 107 | throw unsupported_ops(self, "/", other); 108 | } 109 | } 110 | 111 | public static DObj float_floordiv(DFloat self, DObj other) 112 | { 113 | switch (other) 114 | { 115 | case DFloat v: return MK.Int((int_t) (self.value / v.value)); 116 | case DInt v: return MK.Int((int_t) (self.value / v.value)); 117 | default: 118 | throw unsupported_ops(self, "/", other); 119 | } 120 | } 121 | 122 | public static DObj int_t_truediv(DInt self, DObj other) 123 | { 124 | switch (other) 125 | { 126 | case DFloat v: return MK.Float(self.value / v.value); 127 | case DInt v: return MK.Float(((float) self.value) / v.value); 128 | default: 129 | throw unsupported_ops(self, "/", other); 130 | } 131 | } 132 | 133 | public static DObj float_truediv(DFloat self, DObj other) 134 | { 135 | switch (other) 136 | { 137 | case DFloat v: return MK.Float(self.value / v.value); 138 | case DInt v: return MK.Float(self.value / v.value); 139 | default: 140 | throw unsupported_ops(self, "/", other); 141 | } 142 | } 143 | 144 | 145 | public static DObj int_t_mod(DInt self, DObj other) 146 | { 147 | switch (other) 148 | { 149 | case DFloat v: return MK.Float(s_floatmod(((float) self.value), v.value)); 150 | case DInt v: return MK.Int(s_intmod(self.value, v.value)); 151 | default: 152 | throw unsupported_ops(self, "%", other); 153 | } 154 | } 155 | 156 | public static DObj float_mod(DFloat self, DObj other) 157 | { 158 | switch (other) 159 | { 160 | case DFloat v: return MK.Float(s_floatmod(self.value, v.value)); 161 | case DInt v: return MK.Float(s_floatmod(self.value, v.value)); 162 | default: 163 | throw unsupported_ops(self, "%", other); 164 | } 165 | } 166 | 167 | 168 | static int_t s_intpow(int_t b, int_t pow) 169 | { 170 | int_t result = 1; 171 | while (pow > 0) 172 | { 173 | if ((pow & 1) != 0) 174 | { 175 | result *= b; 176 | } 177 | 178 | pow >>= 1; 179 | b *= b; 180 | } 181 | 182 | return result; 183 | } 184 | 185 | static float f_intpow(float b, int_t pow) 186 | { 187 | float result = 1; 188 | while (pow > 0) 189 | { 190 | if ((pow & 1) != 0) 191 | { 192 | result *= b; 193 | } 194 | 195 | pow >>= 1; 196 | b *= b; 197 | } 198 | 199 | return result; 200 | } 201 | 202 | public static DObj int_t_pow(DInt self, DObj other) 203 | { 204 | switch (other) 205 | { 206 | case DFloat v: return MK.Float(Pow(self.value, v.value)); 207 | case DInt v: 208 | var i = v.value; 209 | if (i < 0) 210 | return MK.Float(Pow(self.value, v.value)); 211 | 212 | return MK.Int(s_intpow(self.value, v.value)); 213 | default: 214 | throw unsupported_ops(self, "**", other); 215 | } 216 | } 217 | 218 | public static DObj float_pow(DFloat self, DObj other) 219 | { 220 | switch (other) 221 | { 222 | case DFloat v: return MK.Float(Pow(self.value, v.value)); 223 | case DInt v: 224 | var i = v.value; 225 | if (i < 0) 226 | return MK.Float(Pow(self.value, v.value)); 227 | return MK.Float(f_intpow(self.value, v.value)); 228 | default: 229 | throw unsupported_ops(self, "**", other); 230 | } 231 | } 232 | 233 | public static DObj int_t_lshift(DInt self, DObj other) 234 | { 235 | switch (other) 236 | { 237 | case DFloat v: throw unsupported_ops(self, "<<", other); 238 | case DInt v: 239 | return MK.Int(unchecked((uint_t) self.value << (int) v.value)); 240 | 241 | 242 | default: 243 | throw unsupported_ops(self, "<<", other); 244 | } 245 | } 246 | 247 | public static DObj int_t_rshift(DInt self, DObj other) 248 | { 249 | switch (other) 250 | { 251 | case DFloat v: throw unsupported_ops(self, ">>", other); 252 | case DInt v: 253 | return MK.Int(unchecked((uint_t) self.value >> (int) v.value)); 254 | default: 255 | throw unsupported_ops(self, ">>", other); 256 | } 257 | } 258 | 259 | public static DObj int_t_bitand(DInt self, DObj other) 260 | { 261 | switch (other) 262 | { 263 | case DFloat v: throw unsupported_ops(self, "&", other); 264 | case DInt v: return MK.Int(self.value & v.value); 265 | default: 266 | throw unsupported_ops(self, "&", other); 267 | } 268 | } 269 | 270 | public static DObj int_t_bitor(DInt self, DObj other) 271 | { 272 | switch (other) 273 | { 274 | case DFloat v: throw unsupported_ops(self, "|", other); 275 | case DInt v: return MK.Int(self.value | v.value); 276 | default: 277 | throw unsupported_ops(self, "|", other); 278 | } 279 | } 280 | 281 | public static DObj int_t_bitxor(DInt self, DObj other) 282 | { 283 | switch (other) 284 | { 285 | case DFloat v: throw unsupported_ops(self, "^", other); 286 | case DInt v: return MK.Int(self.value ^ v.value); 287 | default: 288 | throw unsupported_ops(self, "^", other); 289 | } 290 | } 291 | 292 | 293 | public static bool int_t_lt(DInt self, DObj other) 294 | { 295 | switch (other) 296 | { 297 | case DFloat v: return (float) self.value < v.value; 298 | case DInt v: return self.value < v.value; 299 | default: 300 | throw unsupported_ops(self, "<", other); 301 | } 302 | } 303 | 304 | public static bool int_t_le(DInt self, DObj other) 305 | { 306 | switch (other) 307 | { 308 | case DFloat v: return (float) self.value <= v.value; 309 | case DInt v: return self.value <= v.value; 310 | default: 311 | throw unsupported_ops(self, "<=", other); 312 | } 313 | } 314 | 315 | public static bool int_t_gt(DInt self, DObj other) 316 | { 317 | switch (other) 318 | { 319 | case DFloat v: return (float) self.value > v.value; 320 | case DInt v: return self.value > v.value; 321 | default: 322 | throw unsupported_ops(self, ">", other); 323 | } 324 | } 325 | 326 | public static bool int_t_ge(DInt self, DObj other) 327 | { 328 | switch (other) 329 | { 330 | case DFloat v: return (float) self.value >= v.value; 331 | case DInt v: return self.value >= v.value; 332 | default: 333 | throw unsupported_ops(self, ">=", other); 334 | } 335 | } 336 | 337 | public static bool int_t_eq(DInt self, DObj other) 338 | { 339 | switch (other) 340 | { 341 | case DFloat v: return self.value == v.value; 342 | case DInt v: return self.value == v.value; 343 | default: 344 | return false; 345 | } 346 | } 347 | 348 | public static bool int_t_ne(DInt self, DObj other) 349 | { 350 | switch (other) 351 | { 352 | case DFloat v: return self.value != v.value; 353 | case DInt v: return self.value != v.value; 354 | default: 355 | return true; 356 | } 357 | } 358 | } 359 | 360 | public partial class DFloat 361 | { 362 | public DObj __add__(DObj o) => NumberMethods.float_add(this, o); 363 | public DObj __sub__(DObj o) => NumberMethods.float_sub(this, o); 364 | 365 | public DObj __mul__(DObj o) => NumberMethods.float_mul(this, o); 366 | 367 | public DObj __floordiv__(DObj o) => NumberMethods.float_floordiv(this, o); 368 | public DObj __truediv__(DObj o) => NumberMethods.float_truediv(this, o); 369 | 370 | public DObj __mod__(DObj o) => NumberMethods.float_mod(this, o); 371 | 372 | public DObj __pow__(DObj o) => NumberMethods.float_pow(this, o); 373 | } 374 | 375 | public partial class DInt 376 | { 377 | public DObj __add__(DObj o) => NumberMethods.int_t_add(this, o); 378 | public DObj __sub__(DObj o) => NumberMethods.int_t_sub(this, o); 379 | 380 | public DObj __mul__(DObj o) => NumberMethods.int_t_mul(this, o); 381 | 382 | public DObj __floordiv__(DObj o) => NumberMethods.int_t_floordiv(this, o); 383 | public DObj __truediv__(DObj o) => NumberMethods.int_t_truediv(this, o); 384 | 385 | public DObj __mod__(DObj o) => NumberMethods.int_t_mod(this, o); 386 | 387 | public DObj __pow__(DObj o) => NumberMethods.int_t_pow(this, o); 388 | 389 | public DObj __lshift__(DObj o) => NumberMethods.int_t_lshift(this, o); 390 | 391 | public DObj __rshift__(DObj o) => NumberMethods.int_t_rshift(this, o); 392 | 393 | public bool __eq__(DObj o) => NumberMethods.int_t_eq(this, o); 394 | 395 | public bool __ne__(DObj o) => NumberMethods.int_t_ne(this, o); 396 | 397 | public bool __lt__(DObj o) => NumberMethods.int_t_lt(this, o); 398 | 399 | public bool __gt__(DObj o) => NumberMethods.int_t_gt(this, o); 400 | 401 | public bool __le__(DObj o) => NumberMethods.int_t_le(this, o); 402 | 403 | public bool __ge__(DObj o) => NumberMethods.int_t_ge(this, o); 404 | 405 | public DObj __bitand__(DObj o) => NumberMethods.int_t_bitand(this, o); 406 | public DObj __bitor__(DObj o) => NumberMethods.int_t_bitor(this, o); 407 | public DObj __bitxor__(DObj o) => NumberMethods.int_t_bitxor(this, o); 408 | } 409 | } --------------------------------------------------------------------------------