├── 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 | [](https://github.com/thautwarm/DianaScript/blob/master/docs.md) [](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