├── test ├── code │ ├── trivial.leek │ ├── catch_else.leek │ ├── include │ │ ├── basic.leek │ │ ├── car.class.leek │ │ ├── squared.leek │ │ ├── folder │ │ │ ├── crash.leek │ │ │ └── fact.leek │ │ ├── exception.leek │ │ └── hypot.leek │ ├── exception │ │ ├── catch_else.leek │ │ ├── exception.leek │ │ ├── exception_1.leek │ │ ├── exception_2.leek │ │ ├── exception_3.leek │ │ ├── exception_4.leek │ │ └── exception_5.leek │ ├── fibonacci.leek │ ├── issue │ │ ├── 121.leek │ │ ├── 207_basic.leek │ │ └── 207.leek │ ├── divisors.leek │ ├── fibonacci_long.leek │ ├── fold_left.leek │ ├── fold_right.leek │ ├── sections │ │ ├── sections_foreach.leek │ │ ├── sections_if_then.leek │ │ ├── sections_if_then_else.leek │ │ ├── sections_cells_simple_2.leek │ │ ├── sections_cells_simple_3.leek │ │ ├── sections_cells_simple.leek │ │ └── sections_cells.leek │ ├── fact1000.leek │ ├── return_in_function.leek │ ├── global_functions_1.leek │ ├── fold_left_2.leek │ ├── match.leek │ ├── fold_right_2.leek │ ├── euler │ │ ├── pe003.leek │ │ ├── pe001.leek │ │ ├── pe006.leek │ │ ├── pe009.leek │ │ ├── pe002.leek │ │ ├── pe025.leek │ │ ├── pe004.leek │ │ ├── pe063.leek │ │ ├── pe028.leek │ │ ├── pe016.leek │ │ ├── pe020.leek │ │ ├── pe021.leek │ │ ├── pe007.leek │ │ ├── pe064.leek │ │ ├── pe010.leek │ │ ├── pe005.leek │ │ ├── pe062.leek │ │ ├── pe015.leek │ │ ├── pe066.leek │ │ ├── pe012.leek │ │ ├── pe019.leek │ │ ├── pe206.leek │ │ ├── pe014.leek │ │ ├── pe027.leek │ │ ├── pe023.leek │ │ ├── pe024.leek │ │ ├── pe018.leek │ │ ├── pe017.leek │ │ └── pe008.leek │ ├── two_functions.leek │ ├── dynamic_operators.leek │ ├── primes_gmp.leek │ ├── gcd.leek │ ├── product_n.leek │ ├── quine.leek │ ├── product_n_arrays.leek │ ├── global_functions_2.leek │ ├── product_n_return.leek │ ├── recursive_2_vars.leek │ ├── tarai.leek │ ├── recursive_2_functions.leek │ ├── product_coproduct.leek │ ├── recursive_2_versions.leek │ ├── pow5.leek │ ├── array.leek │ ├── assignments.leek │ ├── euler1.leek │ ├── classes_simple.leek │ ├── recursive_conditions.leek │ ├── loops │ │ ├── lot_of_fors_int.leek │ │ ├── lot_of_fors_array.leek │ │ ├── lot_of_whiles_int.leek │ │ └── lot_of_whiles_array.leek │ ├── strings.leek │ ├── recursive_conditions_2.leek │ ├── primes.leek │ ├── swap.leek │ ├── break_and_continue.leek │ ├── classes_multiple.leek │ ├── mul_array.leek │ ├── quine_zwik.leek │ ├── text_analysis.leek │ ├── project_euler_20.ls │ ├── class.txt │ ├── french.min.leek │ ├── ai.leek │ └── reachable_cells.leek ├── doc.cpp ├── operations.cpp └── util.cpp ├── src ├── analyzer │ ├── semantic │ │ ├── Mutation.cpp │ │ ├── Completion.cpp │ │ ├── Mutation.hpp │ │ ├── Hover.cpp │ │ ├── Hover.hpp │ │ ├── Completion.hpp │ │ ├── Callable.hpp │ │ ├── Callable.cpp │ │ ├── CallableVersion.hpp │ │ └── Call.hpp │ ├── resolver │ │ ├── File.cpp │ │ ├── Resolver.hpp │ │ ├── FileContext.hpp │ │ ├── FileResolver.hpp │ │ ├── VirtualResolver.hpp │ │ ├── FileResolver.cpp │ │ ├── File.hpp │ │ └── VirtualResolver.cpp │ ├── lexical │ │ ├── Ident.cpp │ │ ├── Ident.hpp │ │ ├── Operator.hpp │ │ ├── Todo.hpp │ │ ├── Token.hpp │ │ ├── Location.cpp │ │ ├── Location.hpp │ │ ├── LexicalAnalyzer.hpp │ │ └── Token.cpp │ ├── value │ │ ├── LeftValue.cpp │ │ ├── LeftValue.hpp │ │ ├── Nulll.hpp │ │ ├── String.hpp │ │ ├── Boolean.hpp │ │ ├── Nulll.cpp │ │ ├── ArrayFor.hpp │ │ ├── Phi.cpp │ │ ├── Interval.hpp │ │ ├── Set.hpp │ │ ├── PostfixExpression.hpp │ │ ├── Boolean.cpp │ │ ├── Phi.hpp │ │ ├── AbsoluteValue.hpp │ │ ├── Map.hpp │ │ ├── Object.hpp │ │ ├── If.hpp │ │ ├── PrefixExpression.hpp │ │ ├── String.cpp │ │ ├── Expression.hpp │ │ ├── Array.hpp │ │ ├── Number.hpp │ │ └── ArrayFor.cpp │ ├── PrintOptions.hpp │ ├── instruction │ │ ├── Continue.hpp │ │ ├── Break.hpp │ │ ├── Throw.hpp │ │ ├── Instruction.cpp │ │ ├── Return.hpp │ │ ├── ClassDeclaration.hpp │ │ ├── While.hpp │ │ ├── ExpressionInstruction.hpp │ │ ├── For.hpp │ │ ├── Continue.cpp │ │ ├── Break.cpp │ │ └── VariableDeclaration.hpp │ ├── Result.hpp │ └── Context.hpp ├── doc │ ├── Json_fr.json │ ├── Map_fr.json │ ├── Null_fr.json │ ├── Set_fr.json │ ├── Class_fr.json │ ├── Function_fr.json │ ├── Interval_fr.json │ ├── Object_fr.json │ ├── String_fr.json │ ├── System_fr.json │ ├── Value_fr.json │ ├── Boolean_fr.json │ ├── Documentation.hpp │ ├── Array_fr.json │ ├── Number_fr.json │ └── Documentation.cpp ├── Main.cpp ├── standard │ ├── class │ │ ├── NullSTD.hpp │ │ ├── IntervalSTD.hpp │ │ ├── NullSTD.cpp │ │ ├── JsonSTD.hpp │ │ ├── FunctionSTD.hpp │ │ ├── ClassSTD.hpp │ │ ├── ObjectSTD.hpp │ │ ├── SetSTD.hpp │ │ ├── BooleanSTD.hpp │ │ ├── ClassSTD.cpp │ │ └── MapSTD.hpp │ ├── StandardLibrary.hpp │ └── StandardLibrary.cpp ├── constants.h ├── leekscript.h ├── MainAnalyzer.cpp ├── type │ ├── Never_type.hpp │ ├── Null_type.hpp │ ├── I8_type.hpp │ ├── Mpz_type.hpp │ ├── Real_type.hpp │ ├── Bool_type.hpp │ ├── Class_type.hpp │ ├── Placeholder_type.hpp │ ├── Any_type.hpp │ ├── Never_type.cpp │ ├── Number_type.hpp │ ├── Meta_not_void_type.hpp │ ├── Object_type.hpp │ ├── Meta_add_type.hpp │ ├── Meta_mul_type.hpp │ ├── Meta_temporary_type.hpp │ ├── Meta_add_type.cpp │ ├── Meta_mul_type.cpp │ ├── Meta_concat_type.hpp │ ├── Long_type.hpp │ ├── Meta_not_temporary_type.hpp │ ├── Integer_type.hpp │ ├── Meta_not_void_type.cpp │ ├── Meta_element_type.hpp │ ├── Meta_concat_type.cpp │ ├── Meta_temporary_type.cpp │ ├── Void_type.hpp │ ├── Template_type.hpp │ ├── Meta_element_type.cpp │ ├── Meta_not_temporary_type.cpp │ ├── String_type.hpp │ ├── Interval_type.hpp │ ├── Meta_baseof_type.hpp │ ├── Array_type.hpp │ ├── Placeholder_type.cpp │ ├── Map_type.hpp │ ├── Any_type.cpp │ ├── Meta_baseof_type.cpp │ ├── Struct_type.hpp │ ├── Set_type.hpp │ ├── Void_type.cpp │ ├── Pointer_type.hpp │ ├── Null_type.cpp │ ├── Object_type.cpp │ ├── Fixed_array_type.hpp │ ├── Compound_type.hpp │ ├── Function_object_type.hpp │ ├── Class_type.cpp │ ├── Function_type.hpp │ ├── String_type.cpp │ └── Interval_type.cpp ├── vm │ ├── OutputStream.hpp │ ├── value │ │ ├── LSNull.hpp │ │ ├── LSNull.cpp │ │ ├── LSClosure.hpp │ │ ├── LSClass.hpp │ │ ├── LSClosure.cpp │ │ ├── LSBoolean.hpp │ │ ├── LSInterval.hpp │ │ ├── LSFunction.hpp │ │ └── LSObject.hpp │ └── Exception.hpp ├── util │ └── Util.hpp └── colors.h ├── benchmark ├── code │ ├── cubic_permutations │ │ ├── cubic_permutations.py │ │ ├── cubic_permutations.leek │ │ ├── cubic_permutations.cpp │ │ └── cubic_permutations.java │ ├── factorials │ │ ├── factorials.py │ │ ├── factorials.leek │ │ ├── factorials.cpp │ │ └── factorials.java │ ├── branch_prediction │ │ ├── branch_prediction.leek │ │ ├── branch_prediction.py │ │ ├── branch_prediction.cpp │ │ └── branch_prediction.java │ └── primes_sieve │ │ ├── primes_sieve.leek │ │ ├── primes_sieve.py │ │ ├── primes_sieve.cpp │ │ └── primes_sieve.java └── Benchmark.hpp ├── tool ├── Dockerfile ├── wasm_demo.html ├── wasm_server.py └── demangle.js ├── .gitignore ├── document ├── example_references.leek ├── example_references_balanced.leek ├── example_references_copy_by_default.leek ├── example_references_ref_by_default.leek ├── closure.md ├── glossary.md ├── types.md └── troubleshooting.md ├── .travis.yml └── leekscript.gyp /test/code/trivial.leek: -------------------------------------------------------------------------------- 1 | 2 -------------------------------------------------------------------------------- /src/analyzer/semantic/Mutation.cpp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/doc/Json_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/doc/Map_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/doc/Null_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/doc/Set_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /test/code/catch_else.leek: -------------------------------------------------------------------------------- 1 | [][0] !? 6 -------------------------------------------------------------------------------- /test/code/include/basic.leek: -------------------------------------------------------------------------------- 1 | 'basic' -------------------------------------------------------------------------------- /src/doc/Class_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/doc/Function_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/doc/Interval_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/doc/Object_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/doc/String_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/doc/System_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/doc/Value_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /test/code/exception/catch_else.leek: -------------------------------------------------------------------------------- 1 | (1 % 0) !? 12 -------------------------------------------------------------------------------- /benchmark/code/cubic_permutations/cubic_permutations.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/code/exception/exception.leek: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 % 0 4 | 5 | -------------------------------------------------------------------------------- /test/code/include/car.class.leek: -------------------------------------------------------------------------------- 1 | class Car { 2 | let price = 300000 3 | } -------------------------------------------------------------------------------- /test/code/include/squared.leek: -------------------------------------------------------------------------------- 1 | function squared(x) { 2 | return x ** 2 3 | } -------------------------------------------------------------------------------- /test/code/fibonacci.leek: -------------------------------------------------------------------------------- 1 | let fib = n => n < 2 ? n : fib(n - 1) + fib(n - 2) 2 | fib(30) -------------------------------------------------------------------------------- /test/code/include/folder/crash.leek: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | function crash() { 5 | 2 % 0 6 | } -------------------------------------------------------------------------------- /test/code/issue/121.leek: -------------------------------------------------------------------------------- 1 | [123456789087654321345678976543, 2345678654324567897654324567] -------------------------------------------------------------------------------- /src/analyzer/resolver/File.cpp: -------------------------------------------------------------------------------- 1 | #include "File.hpp" 2 | 3 | namespace ls { 4 | 5 | 6 | } -------------------------------------------------------------------------------- /test/code/divisors.leek: -------------------------------------------------------------------------------- 1 | let divisors = n -> [1..n.sqrt()].filter(x -> !(n % x)) divisors(1989) -------------------------------------------------------------------------------- /test/code/fibonacci_long.leek: -------------------------------------------------------------------------------- 1 | let fib = n => n < 2 ? n : fib(n - 1) + fib(n - 2) 2 | fib(31l) -------------------------------------------------------------------------------- /test/code/fold_left.leek: -------------------------------------------------------------------------------- 1 | [1, 3, 4, 2, 7, 5, 8, 9, 6].foldLeft((acc, x) -> acc.push({w: x}), []) 2 | -------------------------------------------------------------------------------- /test/code/fold_right.leek: -------------------------------------------------------------------------------- 1 | [1, 3, 4, 2, 7, 5, 8, 9, 6].foldRight((x, acc) -> acc.push({w: x}), []) 2 | -------------------------------------------------------------------------------- /test/code/issue/207_basic.leek: -------------------------------------------------------------------------------- 1 | var pq = [] 2 | for x in [1, 2, 3] { 3 | pq = pq + x 4 | } 5 | pq 6 | -------------------------------------------------------------------------------- /test/code/include/exception.leek: -------------------------------------------------------------------------------- 1 | include("folder/crash.leek") 2 | 3 | function except() { 4 | crash() 5 | } -------------------------------------------------------------------------------- /test/code/sections/sections_foreach.leek: -------------------------------------------------------------------------------- 1 | var s = 0 2 | for e in [1, 2, 3, 4, 5] { 3 | s += e 4 | } 5 | s / 5 -------------------------------------------------------------------------------- /test/code/fact1000.leek: -------------------------------------------------------------------------------- 1 | var n = 1m 2 | for var i = 1m; i < 1000m; i = i + 1m { 3 | n = n * i 4 | } 5 | return n 6 | -------------------------------------------------------------------------------- /test/code/sections/sections_if_then.leek: -------------------------------------------------------------------------------- 1 | var a = 12 2 | var b = 0 3 | if (a > 2) { 4 | b = 111 5 | } 6 | 5 * 5 7 | b -------------------------------------------------------------------------------- /test/code/return_in_function.leek: -------------------------------------------------------------------------------- 1 | function f() { 2 | var cells = [12] 3 | cells += [1] 4 | return cells 5 | } 6 | f().size() -------------------------------------------------------------------------------- /test/code/global_functions_1.leek: -------------------------------------------------------------------------------- 1 | var v = is_good(5, 6) 2 | 3 | function is_good(x, y) { 4 | return x == y 5 | } 6 | 7 | v 8 | -------------------------------------------------------------------------------- /test/code/fold_left_2.leek: -------------------------------------------------------------------------------- 1 | function ppair(p, v) { {p: p, v: v} } 2 | [1, 3, 4, 2, 7, 5, 8, 9, 6].foldLeft((pq, x) -> ppair(x, pq), {}) 3 | -------------------------------------------------------------------------------- /test/code/include/folder/fact.leek: -------------------------------------------------------------------------------- 1 | include("../hypot.leek") 2 | let fact = x => x == 1 ? 1 : fact(x - 1) * x 3 | fact(hypot(3, 10).int()) -------------------------------------------------------------------------------- /test/code/include/hypot.leek: -------------------------------------------------------------------------------- 1 | include("squared.leek") 2 | 3 | function hypot(a, b) { 4 | return (squared(a) + squared(b)).sqrt() 5 | } -------------------------------------------------------------------------------- /test/code/match.leek: -------------------------------------------------------------------------------- 1 | let v = "oui" 2 | match v { 3 | "oui": print("Yeah!") 4 | "non": print("snif") 5 | ..: print("ok") 6 | } -------------------------------------------------------------------------------- /tool/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM pilow/leekscript-builder 2 | 3 | MAINTAINER Leek Wars "https://github.com/leek-wars" 4 | 5 | COPY . leekscript 6 | -------------------------------------------------------------------------------- /test/code/fold_right_2.leek: -------------------------------------------------------------------------------- 1 | function ppair(p, v) { {p: p, v: v} } 2 | [1, 3, 4, 2, 7, 5, 8, 9, 6].foldRight((pq, x) -> ppair(x, pq), {}) 3 | -------------------------------------------------------------------------------- /test/code/euler/pe003.leek: -------------------------------------------------------------------------------- 1 | var p = 600851475143 2 | for (var i = 2l; i * i <= p; i++) { 3 | if (p % i == 0) { 4 | p \= i 5 | } 6 | } 7 | p 8 | -------------------------------------------------------------------------------- /test/code/sections/sections_if_then_else.leek: -------------------------------------------------------------------------------- 1 | var a = 12 2 | var b = 0 3 | if (a > 2) { 4 | b = 111 5 | } else { 6 | b = 0 7 | } 8 | 5 * 5 9 | b -------------------------------------------------------------------------------- /test/code/two_functions.leek: -------------------------------------------------------------------------------- 1 | let ppair = (p, v) -> {p: p, v: v} 2 | let pqSingleton = (p, v) -> [{p: p, v: v}] 3 | [ppair(2, 5), pqSingleton(3, 6)] 4 | -------------------------------------------------------------------------------- /test/code/euler/pe001.leek: -------------------------------------------------------------------------------- 1 | var sum = 0 2 | for var n = 0; n < 1000; ++n { 3 | if n % 3 == 0 or n % 5 == 0 { 4 | sum += n 5 | } 6 | } 7 | return sum 8 | -------------------------------------------------------------------------------- /test/code/dynamic_operators.leek: -------------------------------------------------------------------------------- 1 | // Add more iterations to test the speed of a simple operator 2 | var a = 12$ 3 | for var i = 0; i < 100; ++i { 4 | a * 5 5 | } 6 | -------------------------------------------------------------------------------- /test/code/primes_gmp.leek: -------------------------------------------------------------------------------- 1 | var c = 0 2 | 3 | for var i = 1m; i < 100000m; i += 2m { 4 | if i.isPrime() > 0 { 5 | c++ 6 | } 7 | } 8 | 9 | return c 10 | -------------------------------------------------------------------------------- /test/code/gcd.leek: -------------------------------------------------------------------------------- 1 | let gcd = function(a, b) { 2 | while b > 0 { 3 | let c = a % b 4 | a = b 5 | b = c 6 | } 7 | return a 8 | } 9 | 10 | gcd(163231, 135749) -------------------------------------------------------------------------------- /test/code/product_n.leek: -------------------------------------------------------------------------------- 1 | function productN(n) { 2 | if (n == 1) { 3 | 1m; 4 | } else { 5 | n * productN(n - 1); 6 | } 7 | } 8 | productN(7m) 9 | -------------------------------------------------------------------------------- /test/code/quine.leek: -------------------------------------------------------------------------------- 1 | var q=Json.encode('')[0]var a="var q=Json.encode('')[0]var a="+q var b="System.print(a+a+'+q var b='+q+b+q+b)"System.print(a+a+'+q var b='+q+b+q+b) 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Debug/ 2 | Release/ 3 | build/ 4 | *.o 5 | *.d 6 | .metadata/ 7 | .settings/ 8 | .vscode/ 9 | .cproject 10 | .project 11 | documentation.json 12 | doxygen/ 13 | *.ll -------------------------------------------------------------------------------- /src/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "CLI.hpp" 2 | 3 | int main(int argc, char* argv[]) { 4 | ls::CLI cli; 5 | cli.seed_random(); 6 | cli.vm_init(); 7 | return cli.start_full(argc, argv); 8 | } 9 | -------------------------------------------------------------------------------- /test/code/product_n_arrays.leek: -------------------------------------------------------------------------------- 1 | function productN(n) { 2 | if n == [1] { 3 | [1] 4 | } else { 5 | [n[0] * productN([n[0] - 1])[0]] 6 | } 7 | } 8 | productN([7]) 9 | -------------------------------------------------------------------------------- /test/code/global_functions_2.leek: -------------------------------------------------------------------------------- 1 | function is_good(x, y) { 2 | return inc(x) == inc(y) 3 | } 4 | 5 | function inc(x) { 6 | return x + 1 7 | } 8 | 9 | [is_good(5, 6), is_good(6, 6)] 10 | -------------------------------------------------------------------------------- /test/code/product_n_return.leek: -------------------------------------------------------------------------------- 1 | function productN(n) { 2 | if (n == 1) { 3 | return 1m; 4 | } else { 5 | return n * productN(n - 1); 6 | } 7 | } 8 | productN(30m) 9 | -------------------------------------------------------------------------------- /test/code/euler/pe006.leek: -------------------------------------------------------------------------------- 1 | var sum = 0 2 | var squares_sum = 0 3 | 4 | for var n = 1; n <= 100; ++n { 5 | sum += n 6 | squares_sum += n * n 7 | } 8 | 9 | return sum * sum - squares_sum 10 | -------------------------------------------------------------------------------- /test/code/euler/pe009.leek: -------------------------------------------------------------------------------- 1 | for var a = 1; a < 1000; a++ { 2 | for var b = a + 1; b < 1000 - a; b++ { 3 | var c = 1000 - a - b 4 | if a * a + b * b == c * c { 5 | return a * b * c 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/code/recursive_2_vars.leek: -------------------------------------------------------------------------------- 1 | let ack = m, n -> if m == 0 { 2 | n + 1 3 | } else { 4 | if n == 0 { 5 | ack(m - 1, 1) 6 | } else { 7 | ack(m - 1, ack(m, n - 1)) 8 | } 9 | } 10 | ack(3, 7) 11 | -------------------------------------------------------------------------------- /test/code/tarai.leek: -------------------------------------------------------------------------------- 1 | function tarai(x, y, z) { 2 | if x <= y { 3 | y 4 | } else { 5 | tarai(tarai(x - 1, y, z), tarai(y - 1, z, x), tarai(z - 1, x, y)) 6 | } 7 | } 8 | 9 | tarai(16, 13, 5) -------------------------------------------------------------------------------- /src/analyzer/resolver/Resolver.hpp: -------------------------------------------------------------------------------- 1 | #if COMPILER 2 | #include "FileResolver.hpp" 3 | #define Resolver FileResolver 4 | #else 5 | #include "VirtualResolver.hpp" 6 | #define Resolver VirtualResolver 7 | #endif -------------------------------------------------------------------------------- /test/code/euler/pe002.leek: -------------------------------------------------------------------------------- 1 | var f1 = 1 2 | var f2 = 1 3 | var sum = 0 4 | while (f2 < 4000000) { 5 | var n = f1 + f2 6 | f1 = f2 7 | f2 = n 8 | if n % 2 == 0 { 9 | sum += n 10 | } 11 | } 12 | return sum 13 | -------------------------------------------------------------------------------- /document/example_references.leek: -------------------------------------------------------------------------------- 1 | 2 | var a = [1, 2, 3] 3 | 4 | for (var x in a) { 5 | x += 1 6 | f(x) 7 | } 8 | 9 | var b = [] 10 | 11 | function f(x) { 12 | x += 0.5 13 | b.push(x) 14 | } 15 | 16 | b[0] += 10 -------------------------------------------------------------------------------- /test/code/euler/pe025.leek: -------------------------------------------------------------------------------- 1 | var n1 = 1m 2 | var n2 = 1m 3 | 4 | var t = 2 5 | 6 | while |n1.string()| < 1000 { 7 | 8 | var tmp = n1 9 | n1 = n1 + n2 10 | n2 = tmp 11 | 12 | t++ 13 | } 14 | 15 | t -------------------------------------------------------------------------------- /test/code/recursive_2_functions.leek: -------------------------------------------------------------------------------- 1 | // TODO Handle mutually recursive functions 2 | 3 | function fun_real(x) { fun_int((x - 0.5).floor()) } 4 | function fun_int(x) { x > 10 ? fun_real(x - 0.5) : x } 5 | 6 | fun_int(20) 7 | -------------------------------------------------------------------------------- /test/code/product_coproduct.leek: -------------------------------------------------------------------------------- 1 | function coProductN(n, i, acc) { 2 | if (i == n) { 3 | return i * acc; 4 | } else { 5 | return coProductN(n, i + 1, i * acc); 6 | } 7 | } 8 | coProductN(69m, 1m, 1m) 9 | -------------------------------------------------------------------------------- /test/code/recursive_2_versions.leek: -------------------------------------------------------------------------------- 1 | let fun = n -> { 2 | if n < 10 { 3 | n 4 | } else { 5 | if (n.isInteger()) { 6 | fun(n - 0.5) 7 | } else { 8 | fun((n - 0.5).floor()) 9 | } 10 | } 11 | } 12 | fun(20) 13 | -------------------------------------------------------------------------------- /src/analyzer/lexical/Ident.cpp: -------------------------------------------------------------------------------- 1 | #include "Ident.hpp" 2 | 3 | namespace ls { 4 | 5 | Ident::Ident(Token* token) { 6 | this->token = token; 7 | } 8 | 9 | Ident::~Ident() { 10 | // Do not own the token 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /test/code/euler/pe004.leek: -------------------------------------------------------------------------------- 1 | var max = 0 2 | for var a = 999; a >= 100; --a { 3 | for var b = a; b >= 100; --b { 4 | let p = a × b 5 | if p > max and p.isPalindrome() { 6 | max = p 7 | } 8 | } 9 | } 10 | return max 11 | -------------------------------------------------------------------------------- /test/code/euler/pe063.leek: -------------------------------------------------------------------------------- 1 | var c = 0 2 | for (var power = 1m; power < 25m; power++) { 3 | for (var n = 1m; n < 10m; n++) { 4 | var s = '' + (n ** power) 5 | if power == s.size() { 6 | c++ 7 | } 8 | } 9 | } 10 | c 11 | -------------------------------------------------------------------------------- /src/doc/Boolean_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "compare": { 3 | "desc": "Compare deux valeurs booléennes", 4 | "args": { 5 | "a": "Premier booléen", 6 | "b": "Second booléen" 7 | }, 8 | "return": "Resultat : -1, 0 ou 1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/code/euler/pe028.leek: -------------------------------------------------------------------------------- 1 | 2 | 3 | var size = 1001 4 | var n = 1m 5 | var steps = size \ 2 6 | 7 | for i in [1..steps] { 8 | var x = 2*i + 1 9 | n += x*x 10 | n += x*x - 6*i 11 | n += x*x - 4*i 12 | n += x*x - 2*i 13 | } 14 | 15 | n -------------------------------------------------------------------------------- /test/code/euler/pe016.leek: -------------------------------------------------------------------------------- 1 | (2m ** 1000).string().fold((x, y) -> x + y.number(), 0) 2 | 3 | // TODO : only 2 ** 1000 without the m -> detect that it's a large number constant 4 | // TODO : fold the number itself (base 10 by default), iterate over digits as integers 5 | -------------------------------------------------------------------------------- /test/code/pow5.leek: -------------------------------------------------------------------------------- 1 | function pow5(p) { 2 | var x = 1m 3 | var n = 0 4 | while (p > 0) { 5 | if ((p & 1) != 0) { 6 | x *= 5m ** (1 << n) 7 | } 8 | p = p >> 1 9 | n++ 10 | } 11 | x 12 | } 13 | 14 | pow5(57) -------------------------------------------------------------------------------- /test/code/sections/sections_cells_simple_2.leek: -------------------------------------------------------------------------------- 1 | var start = 12 2 | var mp = 10 3 | 4 | var cells = [start] 5 | var grow = [start] 6 | 7 | var res = [] 8 | while (mp--) { 9 | var n = [5, 12] 10 | for c in n { 11 | if true 12 | res += c 13 | } 14 | } 15 | res -------------------------------------------------------------------------------- /benchmark/Benchmark.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BENCHMARK_HPP_ 2 | #define BENCHMARK_HPP_ 3 | 4 | class Benchmark { 5 | public: 6 | Benchmark(); 7 | virtual ~Benchmark(); 8 | 9 | static void arrays(); 10 | static void primes(); 11 | static void operators(); 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/analyzer/semantic/Completion.cpp: -------------------------------------------------------------------------------- 1 | #include "Completion.hpp" 2 | #include "../../environment/Environment.hpp" 3 | 4 | namespace ls { 5 | 6 | Completion::Completion(Environment& env) : type(env.void_) {} 7 | 8 | Completion::Completion(const Type*) : type(type) {} 9 | 10 | } -------------------------------------------------------------------------------- /src/analyzer/semantic/Mutation.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MUTATION_HPP 2 | #define MUTATION_HPP 3 | 4 | namespace ls { 5 | 6 | class Variable; 7 | class Section; 8 | 9 | class Mutation { 10 | public: 11 | Variable* variable; 12 | Section* section; 13 | }; 14 | 15 | } 16 | 17 | #endif -------------------------------------------------------------------------------- /test/code/array.leek: -------------------------------------------------------------------------------- 1 | var a = [] 2 | let n = 12345 3 | 4 | for (var i = 0; i < n; ++i) { 5 | a += i 6 | } 7 | 8 | var b = a.filter(x -> x > 11111) 9 | a = a.map(x -> x + 12).filter(x -> x < 11999) 10 | a = a.map(x -> x - 9999) 11 | 12 | a.foldLeft(x, y -> x + y, -1000) 13 | -------------------------------------------------------------------------------- /document/example_references_balanced.leek: -------------------------------------------------------------------------------- 1 | 2 | var a = [1, 2, 3] 3 | 4 | for (var x in a) { 5 | x += 1 6 | f(x) 7 | } 8 | 9 | var b = [] 10 | 11 | function f(x) { 12 | x += 0.5 13 | b.push(x) 14 | } 15 | 16 | b[0] += 10 17 | 18 | // a = [2, 3, 4] 19 | // b = [12.5, 3.5, 4.5] -------------------------------------------------------------------------------- /src/analyzer/lexical/Ident.hpp: -------------------------------------------------------------------------------- 1 | #ifndef IDENT_HPP_ 2 | #define IDENT_HPP_ 3 | 4 | #include "Token.hpp" 5 | 6 | namespace ls { 7 | 8 | class Ident { 9 | public: 10 | 11 | Token* token; 12 | 13 | Ident(Token* token); 14 | virtual ~Ident(); 15 | }; 16 | 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/standard/class/NullSTD.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NULLSTD_HPP 2 | #define NULLSTD_HPP 3 | 4 | #include "../Module.hpp" 5 | 6 | namespace ls { 7 | 8 | class LSNull; 9 | 10 | class NullSTD : public Module { 11 | public: 12 | NullSTD(Environment& env); 13 | }; 14 | 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /test/code/assignments.leek: -------------------------------------------------------------------------------- 1 | function f() { 2 | var y 3 | let x = 15 4 | if (false) { 5 | if (true) { 6 | return 7 | } else { 8 | y = x 9 | } 10 | } else { 11 | if (true) { 12 | y = x 13 | } else { 14 | y = x 15 | } 16 | } 17 | return y 18 | } 19 | f() 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | group: deprecated-2017Q2 4 | 5 | language: cpp 6 | 7 | services: 8 | - docker 9 | 10 | script: 11 | - 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then make travis-pr; fi' 12 | - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then make travis; fi' 13 | -------------------------------------------------------------------------------- /document/example_references_copy_by_default.leek: -------------------------------------------------------------------------------- 1 | 2 | var a = [1, 2, 3] 3 | 4 | for (var x in a) { 5 | x += 1 6 | f(x) 7 | } 8 | 9 | var b = [] 10 | 11 | function f(x) { 12 | x += 0.5 13 | b.push(x) 14 | } 15 | 16 | b[0] += 10 17 | 18 | // a = [1, 2, 3] 19 | // b = [12.5, 3.5, 4.5] -------------------------------------------------------------------------------- /benchmark/code/factorials/factorials.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | def factorial(n): 4 | f = 1 5 | for i in range(1, n): 6 | f *= i 7 | return f 8 | 9 | c = 0 10 | for i in range(0, 30): 11 | for j in range(1, 1000): 12 | c += factorial(j) + i 13 | c = c % 1000000 14 | 15 | print(c) 16 | -------------------------------------------------------------------------------- /document/example_references_ref_by_default.leek: -------------------------------------------------------------------------------- 1 | 2 | var a = [1, 2, 3] 3 | 4 | for (var x in a) { 5 | x += 1 6 | f(x) 7 | } 8 | 9 | var b = [] 10 | 11 | function f(x) { 12 | x += 0.5 13 | b.push(x) 14 | } 15 | 16 | b[0] += 10 17 | 18 | // a = [12.5, 3.5, 4.5] 19 | // b = [12.5, 3.5, 4.5] -------------------------------------------------------------------------------- /test/code/euler/pe020.leek: -------------------------------------------------------------------------------- 1 | // TODO create a builtin fact function 2 | let fact = x => x == 1 ? 1m : fact(x - 1) * x 3 | 4 | let f = fact(100) 5 | let s = f.string() // TODO mpz.string() directly 6 | 7 | var sum = 0 8 | for (var c in s) { 9 | sum += c.code() - '0'.code() 10 | } 11 | 12 | sum -------------------------------------------------------------------------------- /test/code/euler1.leek: -------------------------------------------------------------------------------- 1 | var n = 100000 2 | 3 | var x3 = Number.floor(n / 3) 4 | var d3 = (x3 * (x3 + 1) / 2) * 3 5 | var x5 = Number.floor((n - 1) / 5) 6 | var d5 = (x5 * (x5 + 1) / 2) * 5 7 | var x15 = Number.floor((n - 1) / 15) 8 | var d15 = (x15 * (x15 + 1) / 2) * 15 9 | 10 | d3 + d5 - d15 11 | -------------------------------------------------------------------------------- /src/analyzer/value/LeftValue.cpp: -------------------------------------------------------------------------------- 1 | #include "LeftValue.hpp" 2 | 3 | namespace ls { 4 | 5 | LeftValue::LeftValue(Environment& env) : Value(env) {} 6 | 7 | bool LeftValue::isLeftValue() const { 8 | return true; 9 | } 10 | void LeftValue::change_value(SemanticAnalyzer*, Value* value) {} 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/constants.h: -------------------------------------------------------------------------------- 1 | #define LEEKSCRIPT_VERSION 2 2 | 3 | #ifndef COMPILER 4 | #define COMPILER 1 // Enable compiler. Usage: web build with analyzer only 5 | #endif 6 | #define DEBUG_PRGM_TYPES 0 7 | #define PRINT_TYPES_COLORS 1 8 | #define STACKTRACE_DETAILS 0 9 | // Disable asserts 10 | // #define NDEBUG -------------------------------------------------------------------------------- /test/code/euler/pe021.leek: -------------------------------------------------------------------------------- 1 | function sumDiv(n) { 2 | var num = 0 3 | for (var i = 1; i < n; ++i) 4 | if (n % i == 0) { 5 | num += i 6 | } 7 | num 8 | } 9 | 10 | function isAmicable(i) { 11 | var sum = sumDiv(i) 12 | sum != i && sumDiv(sum) == i 13 | } 14 | 15 | [1..10000].filter(isAmicable).sum() -------------------------------------------------------------------------------- /src/standard/class/IntervalSTD.hpp: -------------------------------------------------------------------------------- 1 | #ifndef INTERVAL_STD_HPP 2 | #define INTERVAL_STD_HPP 3 | 4 | #include "../Module.hpp" 5 | 6 | namespace ls { 7 | 8 | class IntervalSTD : public Module { 9 | public: 10 | IntervalSTD(Environment& env); 11 | virtual ~IntervalSTD(); 12 | }; 13 | 14 | } 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /test/code/exception/exception_1.leek: -------------------------------------------------------------------------------- 1 | function crash() { 2 | 2 % 0 3 | } 4 | 5 | function power(x) { 6 | let a = 2 7 | crash() 8 | } 9 | 10 | function will_crash(a) { 11 | let b = 3 12 | power(12) 13 | } 14 | 15 | function do_something() { 16 | let c = 4 17 | will_crash(3) 18 | } 19 | 20 | do_something() 21 | -------------------------------------------------------------------------------- /test/code/exception/exception_2.leek: -------------------------------------------------------------------------------- 1 | function crash() { 2 | null - 5 3 | } 4 | 5 | function power(x) { 6 | let a = 2 7 | crash() 8 | } 9 | 10 | function will_crash(a) { 11 | let b = 3 12 | power(12) 13 | } 14 | 15 | function do_something() { 16 | let c = 4 17 | will_crash(3) 18 | } 19 | 20 | do_something() 21 | -------------------------------------------------------------------------------- /test/code/exception/exception_3.leek: -------------------------------------------------------------------------------- 1 | function crash() { 2 | throw 3 | } 4 | 5 | function power(x) { 6 | let a = 2 7 | crash() 8 | } 9 | 10 | function will_crash(a) { 11 | let b = 3 12 | power(12) 13 | } 14 | 15 | function do_something() { 16 | let c = 4 17 | will_crash(3) 18 | } 19 | 20 | do_something() 21 | -------------------------------------------------------------------------------- /test/code/exception/exception_4.leek: -------------------------------------------------------------------------------- 1 | function crash() { 2 | 1000m ** 10000 3 | } 4 | 5 | function power(x) { 6 | let a = 2 7 | crash() 8 | } 9 | 10 | function will_crash(a) { 11 | let b = 3 12 | power(12) 13 | } 14 | 15 | function do_something() { 16 | let c = 4 17 | will_crash(3) 18 | } 19 | 20 | do_something() 21 | -------------------------------------------------------------------------------- /test/code/sections/sections_cells_simple_3.leek: -------------------------------------------------------------------------------- 1 | var start = 12 2 | var mp = 10 3 | 4 | var cells = [start] 5 | var grow = [start] 6 | 7 | while (mp--) { 8 | var res = [] 9 | for x in [1, 2, 3] { 10 | var n = [5, 12] 11 | for c in n { 12 | if true 13 | res += c 14 | } 15 | } 16 | cells += res 17 | } 18 | cells -------------------------------------------------------------------------------- /benchmark/code/branch_prediction/branch_prediction.leek: -------------------------------------------------------------------------------- 1 | let size = 32768 2 | var data = [] 3 | for var i = 0; i < size; ++i { 4 | data += Number.randInt(0, 256) 5 | } 6 | data.sort() 7 | 8 | var sum = 0l 9 | for (var i = 0; i < 70000; ++i) { 10 | for var e in data { 11 | if e >= 128 sum += e 12 | } 13 | } 14 | 15 | System.print(sum) 16 | -------------------------------------------------------------------------------- /src/standard/class/NullSTD.cpp: -------------------------------------------------------------------------------- 1 | #include "NullSTD.hpp" 2 | #include "../../environment/Environment.hpp" 3 | 4 | namespace ls { 5 | 6 | NullSTD::NullSTD(Environment& env) : Module(env, "Null") { 7 | #if COMPILER 8 | env.null_class = std::make_unique(clazz.get()); 9 | lsclass = env.null_class.get(); 10 | #endif 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /test/code/classes_simple.leek: -------------------------------------------------------------------------------- 1 | class Car { 2 | let name = "" 3 | let engine = 5000 4 | } 5 | 6 | var ferrari = Car() 7 | var maserati = new Car 8 | var lamborghini = new Car() 9 | 10 | ferrari.name = "Ferrari" 11 | maserati.name = "Maserati" 12 | lamborghini.name = "Lamborghini" 13 | 14 | [ferrari.name, maserati.name, lamborghini.name] 15 | -------------------------------------------------------------------------------- /test/code/euler/pe007.leek: -------------------------------------------------------------------------------- 1 | function is_prime(n) { 2 | var s = n.sqrt() 3 | for var d = 3; d <= s; d += 2 { 4 | if n % d == 0 { 5 | return false 6 | } 7 | } 8 | return true 9 | } 10 | 11 | var count = 2 12 | var i = 3 13 | while true { 14 | if is_prime(i += 2) { 15 | if ++count == 10001 { 16 | return i 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/code/euler/pe064.leek: -------------------------------------------------------------------------------- 1 | let period = n => { 2 | var s = n.sqrt(), a0 = s.int() 3 | if (n == a0 * a0) return 0 4 | var a = a0 var b = 1 var l = 0 // TODO with commas 5 | while ++l { 6 | b = (n - a * a) \ b 7 | a = b * ((s + a) \ b) - a 8 | if (a == a0 and b == 1) return l 9 | } 10 | } 11 | [2..10000].filter(i => period(i) % 2).size() -------------------------------------------------------------------------------- /test/code/exception/exception_5.leek: -------------------------------------------------------------------------------- 1 | function crash() { 2 | let a = [[], 0][0] 3 | a[0] = 2 4 | } 5 | 6 | function power(x) { 7 | let a = 2 8 | crash() 9 | } 10 | 11 | function will_crash(a) { 12 | let b = 3 13 | power(12) 14 | } 15 | 16 | function do_something() { 17 | let c = 4 18 | will_crash(3) 19 | } 20 | 21 | do_something() 22 | -------------------------------------------------------------------------------- /test/code/recursive_conditions.leek: -------------------------------------------------------------------------------- 1 | function fact(x) { 2 | let a = if x < 5 { 3 | if x == 1 { 4 | 1 5 | } else { 6 | fact(x + 1) * x 7 | } 8 | } else { 9 | if x > 10 { 10 | fact(x - 1) * x 11 | } else { 12 | 1 13 | } 14 | } 15 | if a % 2 { 16 | a 17 | } else { 18 | fact(4) + a 19 | } 20 | } 21 | 22 | fact(12) 23 | -------------------------------------------------------------------------------- /tool/wasm_demo.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/code/loops/lot_of_fors_int.leek: -------------------------------------------------------------------------------- 1 | var c = 0 2 | for var i = 0; i < 3; i++ { 3 | for var j = 0; j < 5; j++ { 4 | for var k = 0; k < 7; k++ { 5 | for var l = 0; l < 11; l++ { 6 | for var m = 0; m < 13; m++ { 7 | c++ 8 | } 9 | } 10 | } 11 | } 12 | } 13 | c -------------------------------------------------------------------------------- /test/code/strings.leek: -------------------------------------------------------------------------------- 1 | let m = ['A', 'T', 'C', 'G'] 2 | var count = 0 3 | var tests = 500 4 | 5 | for var k = 0; k < tests; k++ { 6 | 7 | var adn = '' 8 | for var j = 0; j < 200; j++ { 9 | adn += m[Number.randInt(0, 4)] 10 | } 11 | var contains = adn.contains('GAGA'); 12 | if contains count++ 13 | } 14 | 15 | 100 * (count / tests) // ~ 52% 16 | -------------------------------------------------------------------------------- /test/code/recursive_conditions_2.leek: -------------------------------------------------------------------------------- 1 | function hello(x) { 2 | let a = if x < 5 { 3 | if x == 1 { 4 | '_' 5 | } else { 6 | hello(x + 1) + x 7 | } 8 | } else { 9 | if x > 10 { 10 | hello(x - 1) + x 11 | } else { 12 | '-' 13 | } 14 | } 15 | if x % 2 { 16 | a 17 | } else { 18 | hello(4) + a 19 | } 20 | } 21 | 22 | hello(12) 23 | -------------------------------------------------------------------------------- /src/analyzer/resolver/FileContext.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FILE_RESOLVER_HPP 2 | #define FILE_RESOLVER_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace ls { 8 | 9 | class FileContext { 10 | public: 11 | std::filesystem::path folder; 12 | 13 | FileContext(std::filesystem::path folder = ".") : folder(folder) {} 14 | }; 15 | 16 | } 17 | 18 | #endif -------------------------------------------------------------------------------- /test/code/loops/lot_of_fors_array.leek: -------------------------------------------------------------------------------- 1 | var c = [] 2 | for var i = 0; i < 3; i++ { 3 | for var j = 0; j < 5; j++ { 4 | for var k = 0; k < 7; k++ { 5 | for var l = 0; l < 11; l++ { 6 | for var m = 0; m < 13; m++ { 7 | c += 1 8 | } 9 | } 10 | } 11 | } 12 | } 13 | c.size() -------------------------------------------------------------------------------- /benchmark/code/branch_prediction/branch_prediction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import random 3 | 4 | size = 32768 5 | data = [] 6 | for i in range(0, size): 7 | data.append(random.randint(0, 255)) 8 | data.sort() 9 | 10 | sum = 0 11 | 12 | for i in range(0, 700): 13 | for c in range(0, size): 14 | if data[c] >= 128: 15 | sum += data[c] 16 | 17 | print(sum) 18 | -------------------------------------------------------------------------------- /src/analyzer/resolver/FileResolver.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RESOLVER_HPP 2 | #define RESOLVER_HPP 3 | 4 | #include "File.hpp" 5 | #include 6 | 7 | namespace ls { 8 | 9 | class FileResolver { 10 | public: 11 | File* create(std::string path, Program* program) const; 12 | File* resolve(std::string path, FileContext context) const; 13 | }; 14 | 15 | } 16 | 17 | #endif -------------------------------------------------------------------------------- /src/analyzer/semantic/Hover.cpp: -------------------------------------------------------------------------------- 1 | #include "Hover.hpp" 2 | #include "../../environment/Environment.hpp" 3 | #include "../lexical/Location.hpp" 4 | 5 | namespace ls { 6 | 7 | Hover::Hover(Environment& env) : type(env.void_) {} 8 | 9 | Hover::Hover(const Type* type, Location location, std::string alias) : type(type), location(location), alias(alias) {} 10 | 11 | } 12 | -------------------------------------------------------------------------------- /test/code/primes.leek: -------------------------------------------------------------------------------- 1 | let f = function(number) { 2 | for (var k = 1; 36 * k * k - 12 * k < number; k += 1) { 3 | if (number % (6 * k + 1) == 0) or (number % (6 * k - 1) == 0) { 4 | return false 5 | } 6 | } 7 | return true 8 | } 9 | 10 | var c = 2 11 | 12 | for var i = 5; i < 1000000; i += 6 do 13 | if f(i) c++ 14 | if f(i + 2) c++ 15 | end 16 | 17 | c 18 | -------------------------------------------------------------------------------- /document/closure.md: -------------------------------------------------------------------------------- 1 | # Closure 2 | 3 | Function containing *captured values*, extends normal **Function** 4 | 5 | *captures* : vector 6 | 7 | List of captured values. 8 | 9 | A closure can capture itself. 10 | 11 | 12 | *captures_native* : vector 13 | 14 | TODO check if necessary 15 | 16 | List of boolean indicating if captures are native values 17 | -------------------------------------------------------------------------------- /test/code/sections/sections_cells_simple.leek: -------------------------------------------------------------------------------- 1 | var start = 12 2 | var mp = 10 3 | 4 | var cells = [start] 5 | var grow = [start] 6 | 7 | while mp-- { 8 | var res = [] 9 | for var cell in grow { 10 | var n = [5, 12] 11 | for c in n { 12 | if true 13 | res += c 14 | 15 | } 16 | } 17 | grow = res 18 | cells += res 19 | } 20 | cells -------------------------------------------------------------------------------- /benchmark/code/factorials/factorials.leek: -------------------------------------------------------------------------------- 1 | // TODO f = f * i slower than f *= i 2 | 3 | function factorial(n) { 4 | var f = 1l 5 | for var i = 1; i < n; i++ { 6 | f *= i 7 | } 8 | return f 9 | } 10 | 11 | var c = 0l 12 | for (var i = 1; i < 3000; ++i) { 13 | for (var j = 1; j < 1000; ++j) { 14 | c += factorial(j) + i 15 | } 16 | c = c % 1000000 17 | } 18 | 19 | System.print(c) 20 | -------------------------------------------------------------------------------- /test/code/euler/pe010.leek: -------------------------------------------------------------------------------- 1 | var N = 2000000 2 | var numbers = [] 3 | numbers.fill(1, N + 1) 4 | numbers[1] = 0 5 | 6 | var S = N.sqrt().floor() 7 | for var i = 2; i < S; ++i { 8 | if numbers[i] { 9 | for (var j = i * i; j <= N; j += i) { 10 | numbers[j] = 0 11 | } 12 | } 13 | } 14 | numbers.size() 15 | 16 | var sum = 0l 17 | for i, p in numbers { 18 | if p sum += i 19 | } 20 | sum 21 | -------------------------------------------------------------------------------- /tool/wasm_server.py: -------------------------------------------------------------------------------- 1 | import SimpleHTTPServer 2 | import SocketServer 3 | 4 | PORT = 8765 5 | 6 | class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler): 7 | pass 8 | 9 | Handler.extensions_map['.wasm'] = 'application/wasm' 10 | 11 | httpd = SocketServer.TCPServer(("", PORT), Handler) 12 | 13 | print "Serving at: http://localhost:" + str(PORT) + "/tool/wasm_demo.html" 14 | httpd.serve_forever() -------------------------------------------------------------------------------- /benchmark/code/primes_sieve/primes_sieve.leek: -------------------------------------------------------------------------------- 1 | let f = function(number) { 2 | for (var k = 1; 36 * k * k - 12 * k < number; k += 1) { 3 | if (number % (6 * k + 1) == 0) or (number % (6 * k - 1) == 0) { 4 | return false 5 | } 6 | } 7 | return true 8 | } 9 | 10 | var c = 2 11 | 12 | for var i = 5; i < 8000000; i += 6 do 13 | if f(i) c++ 14 | if f(i + 2) c++ 15 | end 16 | 17 | System.print(c) 18 | -------------------------------------------------------------------------------- /benchmark/code/primes_sieve/primes_sieve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | def is_prime(number): 4 | k = 1 5 | while 36 * k * k - 12 * k < number: 6 | if number % (6 * k + 1) == 0 or number % (6 * k - 1) == 0: 7 | return False 8 | k = k + 1 9 | return True 10 | 11 | c = 2 12 | for i in range(5, 80000, 6): 13 | if is_prime(i): 14 | c = c + 1 15 | if is_prime(i + 2): 16 | c = c + 1 17 | print(c) 18 | -------------------------------------------------------------------------------- /document/glossary.md: -------------------------------------------------------------------------------- 1 | # Glossary 2 | 3 | ## C 4 | 5 | ### CLI 6 | Command Line Interface. It's the entrypoint of LeekScript using command-line. 7 | 8 | ## E 9 | 10 | ### Environment 11 | Contains all the data to execute LeekScript language safely inside a thread. 12 | 13 | ## P 14 | 15 | ### Program 16 | Contains the user code from one or multiple files and provides methods to analyze, compile and run it. 17 | -------------------------------------------------------------------------------- /test/code/euler/pe005.leek: -------------------------------------------------------------------------------- 1 | /* 2 | 1 (2) (3) 4 (5) 6 (7) 8 9 10 (11) 12 (13) 14 15 16 (17) 18 (19) 20 3 | 4 = 2 ^ 2 : two 2 needed 4 | (6 = 2 * 3) 5 | 8 = 2 ^ 3 : three 2 needed 6 | 9 = 3 ^ 2 : two 3 needed 7 | (10 = 5 * 2) 8 | (12 = 3 * 2 ^ 2) 9 | (14 = 2 * 7) 10 | 16 = 2 ^ 4 : four 2 needed 11 | (18 = 2 * 3 ^ 2) 12 | (20 = 2 ^ 2 * 5) 13 | */ 14 | 15 | return (2 ** 4) * (3 ** 2) * 5 * 7 * 11 * 13 * 17 * 19 16 | -------------------------------------------------------------------------------- /test/doc.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.hpp" 2 | #include "../src/doc/Documentation.hpp" 3 | 4 | void Test::test_doc() { 5 | 6 | header("Documentation"); 7 | ls::Documentation doc; 8 | std::ostringstream oss; 9 | doc.generate(oss); 10 | std::cout << oss.str().substr(0, 300) << " [...]" << std::endl; 11 | 12 | doc.generate(oss, "wrong_lang"); 13 | 14 | auto doc2 = new ls::Documentation(); 15 | delete doc2; 16 | } 17 | -------------------------------------------------------------------------------- /src/doc/Documentation.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VM_DOC_DOCUMENTATION_HPP_ 2 | #define VM_DOC_DOCUMENTATION_HPP_ 3 | 4 | #include 5 | #include 6 | #include "../standard/Module.hpp" 7 | 8 | namespace ls { 9 | 10 | class Documentation { 11 | public: 12 | 13 | Documentation(); 14 | virtual ~Documentation(); 15 | 16 | void generate(std::ostream& os, std::string lang = "fr"); 17 | }; 18 | 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/analyzer/lexical/Operator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OPERATOR_HPP 2 | #define OPERATOR_HPP 3 | 4 | #include 5 | #include "Token.hpp" 6 | 7 | namespace ls { 8 | 9 | class Operator { 10 | public: 11 | 12 | Token* token; 13 | TokenType type; 14 | std::string character; 15 | int priority; 16 | bool reversed; 17 | 18 | Operator(Token* token); 19 | 20 | void print(std::ostream&); 21 | }; 22 | 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/standard/class/JsonSTD.hpp: -------------------------------------------------------------------------------- 1 | #ifndef JSON_STD_HPP 2 | #define JSON_STD_HPP 3 | 4 | #include "../Module.hpp" 5 | 6 | namespace ls { 7 | 8 | class JsonSTD : public Module { 9 | public: 10 | JsonSTD(Environment& env); 11 | 12 | #if COMPILER 13 | static Compiler::value encode(Compiler&, std::vector, int); 14 | static LSValue* decode(LSString* string); 15 | #endif 16 | }; 17 | 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /test/code/euler/pe062.leek: -------------------------------------------------------------------------------- 1 | var singles = [] 2 | var groups = ['s' : 12] groups.erase('s') 3 | var first = [:] 4 | var i = 405l 5 | 6 | while i++ { 7 | 8 | var n = '' + i.pow(3) 9 | var ns = n.sort() 10 | 11 | if ns in groups { 12 | var c = groups[ns] = groups[ns] + 1 13 | if (c == 5) { 14 | return String.number(first[ns]) 15 | } 16 | } else { 17 | groups.insert(ns, 1) 18 | first.insert(ns, n) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/code/sections/sections_cells.leek: -------------------------------------------------------------------------------- 1 | var start = 12 2 | var mp = 10 3 | 4 | var cells = [start] 5 | var grow = [start] 6 | 7 | while mp-- { 8 | var res = [] 9 | for var cell in grow { 10 | var n = [5, 12, 302, 515] 11 | for c in n { 12 | if !cells.contains(c) and !res.contains(c) { 13 | res += c 14 | } 15 | } 16 | } 17 | grow = res 18 | cells += res 19 | } -------------------------------------------------------------------------------- /tool/demangle.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | let fs = require("fs") 3 | let spawn = require('child_process').spawnSync 4 | let escape = require('escape-html') 5 | 6 | let file = process.argv[2] 7 | let data = fs.readFileSync(file).toString() 8 | let result = data.replace(/()(.*?)(<\/a><\/td>)/g, function(a, b, c, d) { 9 | return b + escape(spawn('c++filt', [c]).stdout.toString()) + d 10 | }) 11 | console.log(result) 12 | -------------------------------------------------------------------------------- /src/analyzer/PrintOptions.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PRINT_OPTIONS_HPP 2 | #define PRINT_OPTIONS_HPP 3 | 4 | struct PrintOptions { 5 | bool debug = false; 6 | bool condensed = false; 7 | bool sections = false; 8 | bool parenthesis = false; 9 | 10 | PrintOptions add_parenthesis(bool enable = true) { 11 | auto new_options = *this; 12 | new_options.parenthesis = enable; 13 | return new_options; 14 | } 15 | }; 16 | 17 | #endif -------------------------------------------------------------------------------- /test/code/swap.leek: -------------------------------------------------------------------------------- 1 | let siftUp = (c, pq) -> { 2 | if (c > 0) { 3 | let p = (c - 1) >> 1 4 | if (pq[c].p < pq[p].p) { 5 | pq[p] <=> pq[c] 6 | return siftUp(p, pq) 7 | } else { 8 | return pq 9 | } 10 | } else { 11 | return pq 12 | } 13 | } 14 | 15 | let pqInsert = (p, pq) -> { 16 | siftUp(pq.size(), pq.push({p: p})) 17 | } 18 | 19 | var pq = [{p: 4}] 20 | pqInsert(5, pq) 21 | pqInsert(3, pq) 22 | pqInsert(12, pq) 23 | pqInsert(1, pq) 24 | -------------------------------------------------------------------------------- /src/standard/class/FunctionSTD.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FUNCTION_STD_HPP 2 | #define FUNCTION_STD_HPP 3 | 4 | #include "../Module.hpp" 5 | 6 | namespace ls { 7 | 8 | class FunctionSTD : public Module { 9 | public: 10 | FunctionSTD(Environment& env); 11 | 12 | #if COMPILER 13 | static Compiler::value field_return(Compiler& c, Compiler::value a); 14 | static Compiler::value field_args(Compiler& c, Compiler::value a); 15 | #endif 16 | }; 17 | 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /benchmark/code/factorials/factorials.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | long factorial(int number) { 6 | long n = 1; 7 | for (int i = 1; i < number; i++) { 8 | n = n * i; 9 | } 10 | return n; 11 | } 12 | 13 | int main() { 14 | long c = 0; 15 | for (int i = 1; i < 3000; ++i) { 16 | for (int j = 1; j < 1000; ++j) { 17 | c += factorial(j) + i; 18 | } 19 | c = c % 1000000; 20 | } 21 | std::cout << c << std::endl; 22 | } 23 | -------------------------------------------------------------------------------- /src/standard/class/ClassSTD.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLASSSTD_HPP 2 | #define CLASSSTD_HPP 3 | 4 | #include "../Module.hpp" 5 | 6 | namespace ls { 7 | 8 | class ClassSTD : public Module { 9 | public: 10 | ClassSTD(Environment& env); 11 | 12 | #if COMPILER 13 | static void add_field(LSClass* clazz, char* field_name, LSValue* default_value); 14 | 15 | static Compiler::value construct(Compiler& c, std::vector, int); 16 | #endif 17 | }; 18 | 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /test/code/break_and_continue.leek: -------------------------------------------------------------------------------- 1 | var values = [] 2 | 3 | for var i = 0; i < 10; ++i { 4 | var b = [] 5 | for var j = 0; j < 10; ++j { 6 | var c = [] 7 | for var k = 1; k <= 30; ++k { c += k } 8 | b += [c] 9 | } 10 | values += [b] 11 | } 12 | 13 | var sum = 0 14 | for v in values { 15 | for w in v { 16 | for x in w { 17 | if x % 2 { continue } 18 | if x == 18 { continue 2 } 19 | sum += x 20 | if (sum > 2500) { break 3 } 21 | } 22 | } 23 | } 24 | 25 | sum 26 | -------------------------------------------------------------------------------- /test/code/issue/207.leek: -------------------------------------------------------------------------------- 1 | let siftUp = (c, pq) -> { 2 | if (c > 0) { 3 | let p = (c - 1) >> 1 4 | if (pq[c].p < pq[p].p) { 5 | pq[p] <=> pq[c] 6 | return siftUp(p, pq) 7 | } else { 8 | return pq 9 | } 10 | } else { 11 | return pq 12 | } 13 | } 14 | 15 | let pqInsert = (p, v, pq) -> { 16 | siftUp(pq.size(), pq.push({p: p, v: v})) 17 | } 18 | 19 | let xs = [9, 3, 4, 2, 7, 5, 8, 1, 6] 20 | var pq = [] 21 | for x in xs { 22 | pq = pqInsert(x, x, pq) 23 | } 24 | pq 25 | -------------------------------------------------------------------------------- /benchmark/code/factorials/factorials.java: -------------------------------------------------------------------------------- 1 | public class factorials { 2 | 3 | static long factorial(int number) { 4 | long n = 1; 5 | for (int i = 1; i < number; i++) { 6 | n = n * i; 7 | } 8 | return n; 9 | } 10 | 11 | public static void main(String[] args) { 12 | long c = 0; 13 | for (int i = 1; i < 3000; ++i) { 14 | for (int j = 1; j < 1000; ++j) { 15 | c += factorial(j) + i; 16 | } 17 | c = c % 1000000; 18 | } 19 | System.out.println(c); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/code/loops/lot_of_whiles_int.leek: -------------------------------------------------------------------------------- 1 | var i = 2 2 | var c = 0 3 | while (i--) { 4 | var j = 3 5 | while (j--) { 6 | var k = 5 7 | while k-- { 8 | var l = 7 9 | while l-- { 10 | var m = 11 11 | while m-- { 12 | var n = 13 13 | while n-- { 14 | c += 1 15 | } 16 | } 17 | } 18 | } 19 | } 20 | } 21 | c -------------------------------------------------------------------------------- /test/code/loops/lot_of_whiles_array.leek: -------------------------------------------------------------------------------- 1 | var i = 2 2 | var c = [] 3 | while (i--) { 4 | var j = 3 5 | while (j--) { 6 | var k = 5 7 | while k-- { 8 | var l = 7 9 | while l-- { 10 | var m = 11 11 | while m-- { 12 | var n = 13 13 | while n-- { 14 | c += 1 15 | } 16 | } 17 | } 18 | } 19 | } 20 | } 21 | c.size() -------------------------------------------------------------------------------- /src/analyzer/value/LeftValue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LEFTVALUE_HPP_ 2 | #define LEFTVALUE_HPP_ 3 | 4 | #include "Value.hpp" 5 | 6 | namespace ls { 7 | 8 | class LeftValue : public Value { 9 | public: 10 | 11 | LeftValue(Environment& env); 12 | virtual ~LeftValue() = default; 13 | 14 | virtual bool isLeftValue() const override; 15 | virtual void change_value(SemanticAnalyzer*, Value*); 16 | 17 | #if COMPILER 18 | virtual Compiler::value compile_l(Compiler&) const = 0; 19 | #endif 20 | }; 21 | 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /test/code/classes_multiple.leek: -------------------------------------------------------------------------------- 1 | class Engine { 2 | let power = 5000 3 | } 4 | class Wheel { 5 | let diameter = 45.7 6 | } 7 | class Car { 8 | let engine = new Engine() 9 | let wheels = [] 10 | } 11 | 12 | var ferrari = new Car() 13 | for i in [1..4] { 14 | var w = new Wheel 15 | w.diameter = i * 20 16 | ferrari.wheels += w 17 | } 18 | 19 | // TODO not working 20 | // ferrari.wheels.foldLeft((x, s) -> s + x.diameter, 0) 21 | 22 | [ferrari.wheels.size(), ferrari.wheels[1].diameter, ferrari.wheels[3].diameter] 23 | -------------------------------------------------------------------------------- /test/code/euler/pe015.leek: -------------------------------------------------------------------------------- 1 | let S = 20 2 | 3 | var paths = [] // TODO var paths = new Array(20) ? 4 | paths.fill(0, 21) 5 | 6 | let walk = function(x, y) { 7 | if (x + y == S) { 8 | paths[y]++ 9 | return 10 | } 11 | if (x > 0) walk(x - 1, y) 12 | if (y > 0) walk(x, y - 1) 13 | return // TODO useless return here, but prevents a leak 14 | } 15 | 16 | walk(S, S) 17 | 18 | var sum = 1l 19 | for (var i = 0; i < S; ++i) { 20 | var long = (0l + paths[i]) * paths[i] 21 | sum += long 22 | } 23 | return sum 24 | -------------------------------------------------------------------------------- /test/code/euler/pe066.leek: -------------------------------------------------------------------------------- 1 | function solve(D) { 2 | var x = 1l 3 | while x++ { 4 | var s = ((x * x - 1) / D).sqrt() 5 | if s.long() == s { 6 | print((x * x - 1) / D) 7 | print(s) 8 | print(s.long()) 9 | return x 10 | } 11 | } 12 | } 13 | 14 | solve(61) 15 | /* 16 | var max = 0 17 | var maxD = 0 18 | for D in [1..1000] { 19 | if D.sqrt().isInteger() continue 20 | var x = solve(D) 21 | x > max ? { max = x maxD = D } : 0 22 | } 23 | maxD -------------------------------------------------------------------------------- /test/code/euler/pe012.leek: -------------------------------------------------------------------------------- 1 | var n = 50000 2 | var N = 500 3 | var d = [0] 4 | d.fill(0, n + 2) 5 | 6 | for (var i = 1; i <= n + 1; i++) { 7 | for (var j = i; j <= n + 1; j += i) { 8 | d[j]++ 9 | } 10 | } 11 | 12 | var r = 0 13 | var t = 0 14 | for (var i = 1; i <= n; i++) { 15 | var res = 0 16 | if (i & 1) { 17 | res = d[i] * d[(i + 1) \ 2] 18 | } else { 19 | res = d[i \ 2] * d[i + 1] 20 | } 21 | if (res > t) { 22 | t = res 23 | } 24 | if (res > N) { 25 | r = i * (i + 1) \ 2 26 | break 27 | } 28 | } 29 | r 30 | -------------------------------------------------------------------------------- /benchmark/code/primes_sieve/primes_sieve.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool is_prime_fast(int number) { 6 | for (int k = 1; 36 * k * k - 12 * k < number; ++k) { 7 | if ((number % (6 * k + 1) == 0) or (number % (6 * k - 1) == 0)) { 8 | return false; 9 | } 10 | } 11 | return true; 12 | } 13 | 14 | int main() { 15 | int c = 2; 16 | for (int j = 5; j < 8000000; j += 6) { 17 | if (is_prime_fast(j)) c++; 18 | if (is_prime_fast(j + 2)) c++; 19 | } 20 | std::cout << c << std::endl; 21 | } 22 | -------------------------------------------------------------------------------- /src/leekscript.h: -------------------------------------------------------------------------------- 1 | #ifndef LEEKSCRIPT_H__ 2 | #define LEEKSCRIPT_H__ 3 | 4 | #include "constants.h" 5 | 6 | #if COMPILER 7 | #include "vm/VM.hpp" 8 | #include "vm/value/LSObject.hpp" 9 | #include "vm/value/LSArray.hpp" 10 | #endif 11 | #include "util/Util.hpp" 12 | #include "environment/Environment.hpp" 13 | #include "standard/Module.hpp" 14 | #include "analyzer/Program.hpp" 15 | #include "type/Integer_type.hpp" 16 | #include "type/Object_type.hpp" 17 | #include "analyzer/semantic/Callable.hpp" 18 | #include "analyzer/resolver/File.hpp" 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /test/code/mul_array.leek: -------------------------------------------------------------------------------- 1 | // TODO allow 'new' token in v1 2 | 3 | function _mulArrays(arrays) { 4 | 5 | if (count(arrays) == 0) return [] 6 | 7 | var aux = function(stack, neww) { 8 | var res = [] 9 | for (var n in neww) { 10 | for (var e in stack) { 11 | push(res, e + [n]) 12 | } 13 | } 14 | return res 15 | } 16 | 17 | var res = arrayMap(shift(arrays), function(e) { 18 | return [e] 19 | }) 20 | for (var array in arrays) { 21 | res = aux(res, array) 22 | } 23 | return res 24 | } 25 | 26 | _mulArrays([[1, 2, 3], [4, 5, 6]]) 27 | -------------------------------------------------------------------------------- /test/code/quine_zwik.leek: -------------------------------------------------------------------------------- 1 | var s=charAt('\"'0); 2 | var q=charAt('\"'1); 3 | var l=[]; 4 | pushAll(l,[ 5 | "var s=charAt('\"'0);", 6 | "var q=charAt('\"'1);", 7 | "var l=[];", 8 | "pushAll(l,[", 9 | "]);", 10 | "for(var i=0;i<4;i++)debug(replace(l[i],q,s+s+q));", 11 | "for(var i=0;i 5 | #include "Location.hpp" 6 | 7 | namespace ls { 8 | 9 | class Todo { 10 | 11 | public: 12 | 13 | Location location; 14 | std::string content; 15 | 16 | Todo(Location location, const std::string& content) : location(location), content(content) {} 17 | 18 | Json json() const { 19 | return { location.start.line, location.start.column, location.end.line, location.end.column, 2, "TODO", { content } }; 20 | } 21 | }; 22 | 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/analyzer/lexical/Token.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TOKEN_H_ 2 | #define TOKEN_H_ 3 | 4 | #include 5 | #include "Location.hpp" 6 | #include "TokenType.hpp" 7 | 8 | namespace ls { 9 | 10 | class File; 11 | 12 | class Token { 13 | 14 | public: 15 | 16 | TokenType type; 17 | std::string content; 18 | Location location; 19 | unsigned size; 20 | 21 | Token(TokenType type, File* file, size_t raw, size_t line, size_t character, const std::string& content); 22 | }; 23 | 24 | std::ostream& operator << (std::ostream& os, Token& var); 25 | 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/standard/StandardLibrary.hpp: -------------------------------------------------------------------------------- 1 | #ifndef STANDARD_LIBRARY_HPP 2 | #define STANDARD_LIBRARY_HPP 3 | 4 | #include "../analyzer/semantic/Class.hpp" 5 | #include 6 | #include "Module.hpp" 7 | 8 | namespace ls { 9 | 10 | class Environment; 11 | 12 | class StandardLibrary { 13 | public: 14 | Environment& env; 15 | bool legacy = false; 16 | std::unordered_map> classes; 17 | 18 | StandardLibrary(Environment& env, bool legacy = false); 19 | void add_class(std::unique_ptr m); 20 | }; 21 | 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /test/code/text_analysis.leek: -------------------------------------------------------------------------------- 1 | var text = "Le Poireau (Allium porrum) est une espèce de plante herbacée vivace largement cultivée comme plante potagère pour ses feuilles (pseudo-tiges) consommées comme légumes. 2 | Il appartient à la famille des Amaryllidacées (précédemment famille des Liliacées puis des Alliacées). 3 | Noms communs : poireau, porreau, poirée, poirette, asperge du pauvre." 4 | 5 | let lines = text.lines().size() 6 | let words = text.wordCount() 7 | let chars = text.lines().map(x -> x.size()).foldLeft((x, y -> x + y), 0) 8 | 9 | [lines, words, chars] 10 | -------------------------------------------------------------------------------- /src/analyzer/semantic/Hover.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SYNTAXICAL_HOVER_HPP 2 | #define SYNTAXICAL_HOVER_HPP 3 | 4 | #include 5 | #include "../lexical/Location.hpp" 6 | 7 | namespace ls { 8 | 9 | class Type; 10 | class Environment; 11 | 12 | class Hover { 13 | public: 14 | const Type* type; 15 | Location location; 16 | std::string alias = ""; 17 | std::string defined_file = ""; 18 | size_t defined_line = -1; 19 | bool op = false; 20 | 21 | Hover(Environment& env); 22 | Hover(const Type*, Location location, std::string alias = ""); 23 | }; 24 | 25 | } 26 | 27 | #endif -------------------------------------------------------------------------------- /test/code/euler/pe019.leek: -------------------------------------------------------------------------------- 1 | var day = 1 // 1 janvier 1901 => mardi 2 | var sundays = 0 3 | 4 | for (var i = 1901; i <= 2000; ++i) { 5 | 6 | let leap = (i % 100 != 0 && i % 4 == 0) || (i % 400 == 0) 7 | 8 | for (var m = 0; m < 12; ++m) { 9 | 10 | if (day % 7 == 6) sundays++ 11 | 12 | if (m == 3 || m == 5 || m == 8 || m == 10) { 13 | day += 30 14 | } else if (m == 1) { 15 | day += leap ? 29 : 28 16 | } else { 17 | day += 31 18 | } 19 | } 20 | } 21 | 22 | sundays -------------------------------------------------------------------------------- /src/MainAnalyzer.cpp: -------------------------------------------------------------------------------- 1 | #include "CLI.hpp" 2 | #include "environment/Environment.hpp" 3 | 4 | #if WASM 5 | #include 6 | 7 | extern "C" { 8 | const char* EMSCRIPTEN_KEEPALIVE analyze(char* code) { 9 | ls::Environment env; 10 | ls::Program program { env, code, "snippet" }; 11 | env.analyze(program); 12 | std::ostringstream oss; 13 | program.print(oss, true); 14 | return oss.str().c_str(); 15 | } 16 | } 17 | #else 18 | 19 | int main(int argc, char* argv[]) { 20 | ls::CLI cli; 21 | return cli.start_analyzer(argc, argv); 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/analyzer/resolver/VirtualResolver.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VIRTUAL_RESOLVER_HPP 2 | #define VIRTUAL_RESOLVER_HPP 3 | 4 | #include "File.hpp" 5 | #include "FileContext.hpp" 6 | #include 7 | 8 | namespace ls { 9 | 10 | class Program; 11 | 12 | class VirtualResolver { 13 | public: 14 | File* create(std::string path, Program* program) const; 15 | File* delete_(std::string path) const; 16 | File* resolve(std::string path, FileContext context) const; 17 | 18 | static std::unordered_map>& get_cache(); 19 | }; 20 | 21 | } 22 | 23 | #endif -------------------------------------------------------------------------------- /benchmark/code/cubic_permutations/cubic_permutations.leek: -------------------------------------------------------------------------------- 1 | function code(p) { 2 | var groups = ['s' : 12] groups.erase('s') 3 | var first = ['s' : 's'] first.erase('s') 4 | var i = 1 + p 5 | 6 | while i++ { 7 | 8 | var n = '' + i.pow(3) 9 | var ns = n.sort() 10 | 11 | if ns in groups { 12 | groups[ns]++; 13 | if (groups[ns] == 5) { 14 | return String.number(first[ns]) 15 | } 16 | } else { 17 | groups.insert(ns, 1) 18 | first.insert(ns, n) 19 | } 20 | } 21 | } 22 | 23 | var s = 0l 24 | for var i = 0; i < 60; ++i { 25 | s += code(i) 26 | } 27 | System.print(s) 28 | -------------------------------------------------------------------------------- /src/standard/class/ObjectSTD.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OBJECTSTD_HPP 2 | #define OBJECTSTD_HPP 3 | 4 | #include "../Module.hpp" 5 | 6 | namespace ls { 7 | 8 | class LSObject; 9 | class LSNumber; 10 | 11 | class ObjectSTD : public Module { 12 | public: 13 | ObjectSTD(Environment& env); 14 | ~ObjectSTD(); 15 | 16 | #if COMPILER 17 | 18 | std::unique_ptr readonly; 19 | std::unique_ptr readonly_value; 20 | 21 | static Compiler::value in_any(Compiler& c, std::vector args, int); 22 | static LSValue* object_new(LSClass* clazz); 23 | 24 | #endif 25 | }; 26 | 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /benchmark/code/branch_prediction/branch_prediction.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | const unsigned arraySize = 32768; 7 | int data[arraySize]; 8 | for (unsigned c = 0; c < arraySize; ++c) { 9 | data[c] = std::rand() % 256; 10 | } 11 | std::sort(data, data + arraySize); 12 | 13 | long sum = 0; 14 | for (unsigned i = 0; i < 70000; i++) { 15 | for (unsigned c = 0; c < arraySize; ++c) { 16 | if (data[c] >= 128) 17 | sum += data[c]; 18 | } 19 | } 20 | std::cout << sum << std::endl; 21 | } 22 | -------------------------------------------------------------------------------- /src/analyzer/lexical/Location.cpp: -------------------------------------------------------------------------------- 1 | #include "Location.hpp" 2 | 3 | namespace ls { 4 | 5 | Position Position::after() const { 6 | return { line, column + 1, raw + 1 }; 7 | } 8 | 9 | Json Position::json() const { 10 | return Json::array({ 11 | line, column, raw 12 | }); 13 | } 14 | 15 | bool Location::contains(size_t position) const { 16 | return position >= start.raw and position <= end.raw; 17 | } 18 | 19 | Location Location::after() const { 20 | return { file, end.after(), end.after() }; 21 | } 22 | 23 | Json Location::json() const { 24 | return Json::array({ 25 | start.json(), end.json() 26 | }); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /src/type/Never_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NEVER_TYPE_HPP 2 | #define NEVER_TYPE_HPP 3 | 4 | #include "Any_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Never_type : public Any_type { 9 | public: 10 | Never_type(Environment&); 11 | virtual ~Never_type() {} 12 | virtual const std::string getName() const override { return "never"; } 13 | virtual Json json() const override; 14 | virtual bool operator == (const Type*) const override; 15 | virtual int distance(const Type* type) const override; 16 | virtual std::ostream& print(std::ostream& os) const override; 17 | virtual Type* clone() const override; 18 | }; 19 | 20 | } 21 | 22 | #endif -------------------------------------------------------------------------------- /src/analyzer/semantic/Completion.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMPLETION_HPP 2 | #define COMPLETION_HPP 3 | 4 | #include "../lexical/Location.hpp" 5 | 6 | namespace ls { 7 | 8 | class Environment; 9 | class Type; 10 | 11 | enum class CompletionType { 12 | METHOD, 13 | FIELD, 14 | VARIABLE 15 | }; 16 | 17 | class CompletionItem { 18 | public: 19 | std::string name; 20 | CompletionType type; 21 | const Type* lstype; 22 | Location location; 23 | }; 24 | 25 | class Completion { 26 | public: 27 | const Type* type; 28 | std::vector items; 29 | 30 | Completion(Environment&); 31 | Completion(const Type*); 32 | }; 33 | 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /src/analyzer/value/Nulll.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NULLL_HPP 2 | #define NULLL_HPP 3 | 4 | #include 5 | #include "Value.hpp" 6 | #include "../lexical/Token.hpp" 7 | 8 | namespace ls { 9 | 10 | class Nulll : public Value { 11 | public: 12 | 13 | Token* token; 14 | 15 | Nulll(Environment& env, Token* token); 16 | 17 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 18 | virtual Location location() const override; 19 | 20 | #if COMPILER 21 | virtual Compiler::value compile(Compiler&) const override; 22 | #endif 23 | 24 | virtual std::unique_ptr clone(Block* parent) const override; 25 | }; 26 | 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/vm/OutputStream.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OUTPUT_STREAM_HPP 2 | #define OUTPUT_STREAM_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace ls { 8 | 9 | class OutputStream { 10 | public: 11 | virtual std::ostream& stream() { 12 | return std::cout; 13 | } 14 | virtual void end() { 15 | std::cout << std::endl; 16 | } 17 | }; 18 | 19 | class OutputStringStream : public ls::OutputStream { 20 | std::ostringstream oss; 21 | public: 22 | virtual std::ostream& stream() override { 23 | return oss; 24 | } 25 | virtual void end() override { 26 | oss << std::endl; 27 | } 28 | std::string str() const { 29 | return oss.str(); 30 | } 31 | }; 32 | 33 | } 34 | 35 | #endif -------------------------------------------------------------------------------- /test/code/euler/pe206.leek: -------------------------------------------------------------------------------- 1 | var res = '' 2 | var search = function(start, base, level) { 3 | if (level == 5) { 4 | var b = base + (10m ** (20 - 2 * level)) 5 | for (var j = Number.sqrt(start); j < Number.sqrt(b); ++j) { 6 | var s = '' + (j ** 2) 7 | for var k = 0; k < 9; { 8 | if s[k * 2] != ('' + (++k)) continue 2 9 | } 10 | res += ('' + j) 11 | } 12 | } else { 13 | for var i = 0m; i < 10m; ++i { 14 | var p = i * (10m ** (19 - 2 * level)) 15 | var a = start + p 16 | var b = base + (level + 1) * (10m ** (18 - 2 * level)) + p 17 | search(a, b, level + 1) 18 | } 19 | } 20 | } 21 | 22 | search(1020304050607080900m, 1000000000000000000m, 1) 23 | 24 | res.number() 25 | -------------------------------------------------------------------------------- /test/code/project_euler_20.ls: -------------------------------------------------------------------------------- 1 | var digits = [1] 2 | 3 | for var p = 1; p <= 100; p++ { 4 | for var j = 0; j < digits.size(); j++ { 5 | digits[j] *= p 6 | } 7 | for var i = 0; i < digits.size(); i++ { 8 | if (9 < digits[i]) { 9 | let m = digits[i] % 10 10 | var q = (digits[i] - m) / 10 11 | digits[i] = m 12 | if (i < digits.size() - 1) { 13 | digits[i + 1] += q 14 | } else { 15 | digits += q 16 | break 17 | } 18 | } 19 | } 20 | var n = digits.size() - 1 21 | while (9 < digits[n]) { 22 | let mo = digits[n] % 10 23 | let qu = (digits[n] - mo) / 10 24 | digits[n] = mo 25 | digits += qu 26 | n++ 27 | } 28 | } 29 | // print(~digits) 30 | digits.sum() 31 | -------------------------------------------------------------------------------- /test/code/class.txt: -------------------------------------------------------------------------------- 1 | class A extends B { 2 | const STATIC_CLASS_CONSTANT = 12; 3 | let constant_field 4 | var mutable_field = 0 5 | constructor(a) => constant_field = a 6 | constructor() { 7 | mutable_field = 12 8 | } 9 | update() { ... } 10 | update2() => ... 11 | let f = () => 'salut' // function field 12 | } 13 | class Operation { 14 | let op = + 15 | constructor(op) => this.op = op 16 | operator () (a, b) { 17 | return op(a, b) 18 | } 19 | run(a, b) => op(a, b) 20 | } 21 | let plus = new Operation(×) 22 | plus(5, 6) 23 | plus.run(5, 6) 24 | 25 | var a 26 | const a 27 | var a = [] 28 | function() { return 'salut' } 29 | function m() { return 'salut' } 30 | () => 'salut' 31 | m() => 'salut' -------------------------------------------------------------------------------- /document/types.md: -------------------------------------------------------------------------------- 1 | *any* 2 | .class, print, string(), json() 3 | 4 | *number* 5 | all math 6 | *casts* : *bool*, *integer* 7 | 8 | *integer* = *number* 9 | *bool* = *integer* 10 | print as true/false 11 | 12 | *list* 13 | size(), map(), iter() 14 | *list* 15 | sum(), average(), min(), max() 16 | 17 | *map* = *list* 18 | 19 | *array* = *list* 20 | push(V), remove(i) 21 | 22 | *string* = *list* 23 | uppercase(), lowercase() 24 | *char* = *string<1>* + *integer* 25 | 26 | *interval* = *list* 27 | 28 | *set* = *list* 29 | add(V) 30 | 31 | *object* = *list* 32 | 33 | *function* = { 34 | args = *list* 35 | } 36 | *class* -------------------------------------------------------------------------------- /src/type/Null_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NULL_TYPE_HPP 2 | #define NULL_TYPE_HPP 3 | 4 | #include "Pointer_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Null_type : public Pointer_type { 9 | public: 10 | Null_type(Environment& env); 11 | virtual int id() const override { return 1; } 12 | virtual const std::string getName() const override { return "null"; } 13 | virtual Json json() const override; 14 | virtual bool operator == (const Type*) const override; 15 | virtual int distance(const Type* type) const override; 16 | virtual std::string class_name() const override; 17 | virtual std::ostream& print(std::ostream& os) const override; 18 | virtual Type* clone() const override; 19 | }; 20 | 21 | } 22 | 23 | #endif -------------------------------------------------------------------------------- /src/util/Util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_HPP_ 2 | #define UTIL_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ls { 9 | 10 | class Util { 11 | public: 12 | 13 | static std::string read_file(std::string file); 14 | static std::vector read_file_lines(std::string file); 15 | static bool is_file_name(std::string data); 16 | static std::string replace_all(std::string& haystack, const std::string& needle, const std::string& replacement); 17 | static std::string file_short_name(std::string path); 18 | 19 | static std::string toupper(const std::string& string); 20 | static std::string tolower(const std::string& string); 21 | }; 22 | 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /test/code/euler/pe014.leek: -------------------------------------------------------------------------------- 1 | let N = 1000000 2 | var cache = [] 3 | cache.fill(0, N) 4 | cache[1] = 1 5 | 6 | let sequence_length = function(n) { 7 | if (n >= N) { 8 | return if n % 2 { 9 | 1 + Number.long(sequence_length(n * 3 + 1)) 10 | } else { 11 | 1 + Number.long(sequence_length(n / 2)) 12 | } 13 | } 14 | var c = cache[n] 15 | if c return c 16 | 17 | return cache[n] = if n % 2 { 18 | 1 + Number.long(sequence_length(n * 3 + 1)) 19 | } else { 20 | 1 + Number.long(sequence_length(n / 2)) 21 | } 22 | } 23 | 24 | var max = 0 25 | var n = 0 26 | 27 | for var i = 1l; i < 1000000; i++ { 28 | var l = sequence_length(i) 29 | if l > max { 30 | max = l 31 | n = i 32 | } 33 | } 34 | 35 | n 36 | -------------------------------------------------------------------------------- /src/analyzer/value/String.hpp: -------------------------------------------------------------------------------- 1 | #ifndef STRING_HPP_ 2 | #define STRING_HPP_ 3 | 4 | #include "Value.hpp" 5 | 6 | namespace ls { 7 | 8 | class Token; 9 | 10 | class String : public Value { 11 | public: 12 | 13 | Token* token; 14 | 15 | String(Environment& env, Token* token); 16 | 17 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 18 | virtual Location location() const override; 19 | 20 | virtual bool will_store(SemanticAnalyzer* analyzer, const Type* type) override; 21 | 22 | #if COMPILER 23 | virtual Compiler::value compile(Compiler&) const override; 24 | #endif 25 | 26 | virtual std::unique_ptr clone(Block* parent) const override; 27 | }; 28 | 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/analyzer/value/Boolean.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOLEAN_HPP 2 | #define BOOLEAN_HPP 3 | 4 | #include 5 | #include "Value.hpp" 6 | #include "../lexical/Token.hpp" 7 | #include "../semantic/SemanticAnalyzer.hpp" 8 | 9 | namespace ls { 10 | 11 | class Boolean : public Value { 12 | public: 13 | 14 | Token* token; 15 | bool value; 16 | 17 | Boolean(Environment& env, Token* token); 18 | 19 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 20 | virtual Location location() const override; 21 | 22 | #if COMPILER 23 | virtual Compiler::value compile(Compiler&) const override; 24 | #endif 25 | 26 | virtual std::unique_ptr clone(Block* parent) const override; 27 | }; 28 | 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /test/code/french.min.leek: -------------------------------------------------------------------------------- 1 | function _(n) { 2 | var T = '-', V = '', x = split('s un deux trois quatre cinq six sept huit neuf dix onze douze treize quatorze quinze seize dix vingt trente quarante cinquante soixante quatre-vingt cent' ' '), b = n % 100, d = int(17 + b / 10), u = n % 10, c = floor(n / 100), e = u - 1 ? T : '-et-', L = int(log10(n) / 3), H = 1000 ** L, v = floor(n / H), i = [T ' ' x[d] ? 0 : d-- or (u += 10)][L > 1] 3 | return (L < 1) ? c ? (c > 1 ? _(c) + T : '') + x[27] + x[c * !b < 2] + (b ? T : '') + _(b) : n < 17 ? x[n + 1] : n < 20 ? x[11] + '-' + x[u + 1] : x[d] + (u ? e + _(u) : x[d != 25]) : (L * v > 1 ? _(v) + i : '') + 'mill' + [n %= H 'e' 'ion' 'iard'][L] + x[v < 2 or L < 2] + (n ? i : '') + _(n) 4 | } 5 | _(987654321012) 6 | -------------------------------------------------------------------------------- /src/analyzer/instruction/Continue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONTINUE_HPP 2 | #define CONTINUE_HPP 3 | 4 | #include "Instruction.hpp" 5 | 6 | namespace ls { 7 | 8 | class Continue : public Instruction { 9 | public: 10 | 11 | int deepness; 12 | Token* token = nullptr; 13 | 14 | Continue(Environment& env); 15 | 16 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 17 | virtual Location location() const override; 18 | 19 | virtual void analyze(SemanticAnalyzer*, const Type* req_type) override; 20 | 21 | #if COMPILER 22 | virtual Compiler::value compile(Compiler&) const override; 23 | #endif 24 | 25 | virtual std::unique_ptr clone(Block* parent) const override; 26 | }; 27 | 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/type/I8_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef I8_TYPE_HPP 2 | #define I8_TYPE_HPP 3 | 4 | #include "Number_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class I8_type : public Number_type { 9 | public: 10 | I8_type(Environment& env) : Number_type(env) {} 11 | virtual const std::string getName() const override { return "i8"; } 12 | virtual Json json() const override; 13 | virtual bool operator == (const Type*) const override; 14 | virtual int distance(const Type* type) const override; 15 | #if COMPILER 16 | virtual llvm::Type* llvm(Compiler& c) const override; 17 | #endif 18 | virtual std::string class_name() const override; 19 | virtual std::ostream& print(std::ostream&) const override; 20 | virtual Type* clone() const override; 21 | }; 22 | 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /src/type/Mpz_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MPZ_TYPE_HPP 2 | #define MPZ_TYPE_HPP 3 | 4 | #include "Number_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Mpz_type : public Number_type { 9 | public: 10 | Mpz_type(Environment& env) : Number_type(env) {} 11 | virtual const std::string getName() const override { return "mpz"; } 12 | virtual Json json() const override; 13 | virtual bool operator == (const Type*) const override; 14 | virtual int distance(const Type* type) const override; 15 | #if COMPILER 16 | virtual llvm::Type* llvm(Compiler& c) const override; 17 | #endif 18 | virtual std::string class_name() const override; 19 | virtual std::ostream& print(std::ostream& os) const override; 20 | virtual Type* clone() const override; 21 | }; 22 | 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /benchmark/code/branch_prediction/branch_prediction.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.Random; 3 | 4 | public class branch_prediction { 5 | public static void main(String[] args) { 6 | 7 | int arraySize = 32768; 8 | int data[] = new int[arraySize]; 9 | Random rnd = new Random(0); 10 | for (int c = 0; c < arraySize; ++c) { 11 | data[c] = rnd.nextInt() % 256; 12 | } 13 | Arrays.sort(data); 14 | 15 | long sum = 0; 16 | 17 | for (int i = 0; i < 70000; ++i) { 18 | for (int c = 0; c < arraySize; ++c) { 19 | if (data[c] >= 128) 20 | sum += data[c]; 21 | } 22 | } 23 | System.out.println(sum); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/type/Real_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef REAL_TYPE_HPP 2 | #define REAL_TYPE_HPP 3 | 4 | #include "Number_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Real_type : public Number_type { 9 | public: 10 | Real_type(Environment& env) : Number_type(env) {} 11 | virtual const std::string getName() const override { return "real"; } 12 | virtual Json json() const override; 13 | virtual bool operator == (const Type*) const override; 14 | virtual int distance(const Type* type) const override; 15 | #if COMPILER 16 | virtual llvm::Type* llvm(Compiler& c) const override; 17 | #endif 18 | virtual std::string class_name() const override; 19 | virtual std::ostream& print(std::ostream& os) const override; 20 | virtual Type* clone() const override; 21 | }; 22 | 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /document/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | ## General 4 | 5 | ### Phi nodes 6 | - The phi node should be *the first instruction of a block* 7 | - Input blocks must be direct predecessor of the phi's block, but for input values it's more permissive. 8 | 9 | ## Errors 10 | - llvm::LiveVariables::HandleVirtRegUse(unsigned int, llvm::MachineBasicBlock*, llvm::MachineInstr&) () from /usr/lib/x86_64-linux-gnu/libLLVM-8.so.1 11 | => In a function, a variable from another function is used. 12 | - Program received signal SIGSEGV, Segmentation fault. 0x00007ffffbf573a2 in llvm::Function::getPersonalityFn() const () from /usr/lib/x86_64-linux-gnu/libLLVM-8.so.1 13 | => A function tries to throw something but didn't declare `throws` attribute so the main function doesn't setup the personality function. -------------------------------------------------------------------------------- /src/type/Bool_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOL_TYPE_HPP 2 | #define BOOL_TYPE_HPP 3 | 4 | #include "Type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Bool_type : public Type { 9 | public: 10 | Bool_type(Environment& env) : Type(env, true) {} 11 | virtual int id() const override { return 2; } 12 | virtual const std::string getName() const override { return "bool"; } 13 | virtual Json json() const override; 14 | virtual bool operator == (const Type*) const override; 15 | virtual int distance(const Type*) const override; 16 | #if COMPILER 17 | virtual llvm::Type* llvm(Compiler& c) const override; 18 | #endif 19 | virtual std::string class_name() const override; 20 | virtual std::ostream& print(std::ostream& os) const override; 21 | virtual Type* clone() const override; 22 | }; 23 | 24 | } 25 | 26 | #endif -------------------------------------------------------------------------------- /src/type/Class_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLASS_TYPE_HPP 2 | #define CLASS_TYPE_HPP 3 | 4 | #include "Pointer_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Class_type : public Pointer_type { 9 | std::string name; 10 | public: 11 | Class_type(Environment& env, std::string name); 12 | virtual int id() const override { return 11; } 13 | virtual const std::string getName() const override; 14 | virtual Json json() const override; 15 | virtual bool operator == (const Type*) const override; 16 | virtual bool callable() const override { return true; } 17 | virtual int distance(const Type* type) const override; 18 | virtual std::string class_name() const override; 19 | virtual std::ostream& print(std::ostream& os) const override; 20 | virtual Type* clone() const override; 21 | }; 22 | 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /src/analyzer/value/Nulll.cpp: -------------------------------------------------------------------------------- 1 | #include "Nulll.hpp" 2 | #include "../../type/Type.hpp" 3 | #include "../semantic/SemanticAnalyzer.hpp" 4 | 5 | namespace ls { 6 | 7 | Nulll::Nulll(Environment& env, Token* token) : Value(env), token(token) { 8 | type = env.null; 9 | constant = true; 10 | } 11 | 12 | void Nulll::print(std::ostream& os, int, PrintOptions options) const { 13 | os << "null"; 14 | if (options.debug) { 15 | os << " " << type; 16 | } 17 | } 18 | 19 | Location Nulll::location() const { 20 | return token->location; 21 | } 22 | 23 | #if COMPILER 24 | Compiler::value Nulll::compile(Compiler& c) const { 25 | return c.new_null(); 26 | } 27 | #endif 28 | 29 | std::unique_ptr Nulll::clone(Block* parent) const { 30 | return std::make_unique(type->env, token); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/analyzer/instruction/Break.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BREAK_HPP 2 | #define BREAK_HPP 3 | 4 | #include 5 | #include "Instruction.hpp" 6 | #include "../lexical/Token.hpp" 7 | 8 | namespace ls { 9 | 10 | class Environment; 11 | 12 | class Break : public Instruction { 13 | public: 14 | 15 | Token* token; 16 | int deepness; 17 | 18 | Break(Environment& env); 19 | 20 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 21 | virtual Location location() const override; 22 | 23 | virtual void analyze(SemanticAnalyzer*, const Type* req_type) override; 24 | 25 | #if COMPILER 26 | virtual Compiler::value compile(Compiler&) const override; 27 | #endif 28 | 29 | virtual std::unique_ptr clone(Block* parent) const override; 30 | }; 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/vm/value/LSNull.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LSNULL 2 | #define LSNULL 3 | 4 | #include 5 | #include 6 | #include "../LSValue.hpp" 7 | 8 | namespace ls { 9 | 10 | class LSNull : public LSValue { 11 | private: 12 | static LSValue* null_var; 13 | LSNull(); 14 | 15 | public: 16 | static LSValue* get(); 17 | static LSNull* create() { 18 | return new LSNull(); 19 | } 20 | static void set_null_value(LSNull* null_value) { 21 | LSNull::null_var = null_value; 22 | } 23 | 24 | ~LSNull(); 25 | 26 | bool to_bool() const override; 27 | bool ls_not() const override; 28 | bool eq(const LSValue*) const override; 29 | bool lt(const LSValue*) const override; 30 | std::ostream& dump(std::ostream& os, int level) const override; 31 | LSValue* getClass(VM* vm) const override; 32 | }; 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/colors.h: -------------------------------------------------------------------------------- 1 | #if WASM 2 | #define C_GREY "" 3 | #define C_GREEN "" 4 | #define C_RED "" 5 | #define C_PURPLE "" 6 | #define C_BLUE "" 7 | #define C_YELLOW "" 8 | #define C_PINK "" 9 | #define C_CYAN "" 10 | #define BOLD "" 11 | #define BLUE_BOLD "" 12 | #define GREEN_BOLD "" 13 | #define END_COLOR "" 14 | #define UNDERLINE "" 15 | #define END_STYLE "" 16 | #else 17 | #define C_GREY "\033[0;90m" 18 | #define C_GREEN "\033[0;32m" 19 | #define C_RED "\033[1;31m" 20 | #define C_PURPLE "\033[1;35m" 21 | #define C_BLUE "\033[0;34m" 22 | #define C_YELLOW "\033[1;33m" 23 | #define C_CYAN "\033[1;96m" 24 | #define C_PINK "\033[1;95m" 25 | #define BOLD "\033[1;1m" 26 | #define BLUE_BOLD "\033[1;34m" 27 | #define GREEN_BOLD "\033[1;32m" 28 | #define END_COLOR "\033[0m" 29 | #define UNDERLINE "\e[4m" 30 | #define END_STYLE "\e[0m" 31 | #endif -------------------------------------------------------------------------------- /test/code/euler/pe027.leek: -------------------------------------------------------------------------------- 1 | function numPrimes(a, b) { 2 | var n = 0 3 | // TODO while (n*n + a*n + b).isPrime() not working 4 | while ((n*n + a*n + b).isPrime()) { n++ } 5 | return n 6 | } 7 | 8 | // print(numPrimes(-79, 1601)) 9 | 10 | var max = 0; 11 | var maxA = 0, maxB = 0; 12 | 13 | for (var a = -999; a < 1000; ++a) { 14 | for (var b = -999; b < 1000; ++b) { 15 | 16 | if (b.isPrime()) { // b doit etre premier ! 17 | 18 | var num = numPrimes(a, b); 19 | if (num > max) { 20 | max = num 21 | maxA = a 22 | maxB = b 23 | } 24 | } 25 | } 26 | } 27 | /* 28 | print("Nombre de premiers : " + max) 29 | print("a : " + maxA) 30 | print("b : " + maxB) 31 | print("ab : " + maxA * maxB) 32 | */ 33 | return maxA * maxB 34 | -------------------------------------------------------------------------------- /src/analyzer/lexical/Location.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LOCATION_HPP_ 2 | #define LOCATION_HPP_ 3 | 4 | #include 5 | #include "../../util/json.hpp" 6 | 7 | namespace ls { 8 | 9 | class File; 10 | 11 | struct Position { 12 | size_t line = 0; 13 | size_t column = 0; 14 | size_t raw = 0; 15 | Position() {} 16 | Position(size_t line, size_t column, size_t raw) : 17 | line(line), column(column), raw(raw) {} 18 | 19 | Position after() const; 20 | Json json() const; 21 | }; 22 | 23 | struct Location { 24 | File* file = nullptr; 25 | Position start; 26 | Position end; 27 | Location() {} 28 | Location(File* file, Position start, Position end) : file(file), start(start), end(end) {} 29 | 30 | bool contains(size_t position) const; 31 | Location after() const; 32 | Json json() const; 33 | }; 34 | 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/type/Placeholder_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PLACEHOLDER_TYPE_HPP 2 | #define PLACEHOLDER_TYPE_HPP 3 | 4 | #include "Any_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Type; 9 | 10 | class Placeholder_type : public Any_type { 11 | std::string _name; 12 | const Type* _implementation = nullptr; 13 | const Type* _element = nullptr; 14 | public: 15 | Placeholder_type(Environment& env, const std::string name) : Any_type(env), _name(name) { 16 | placeholder = true; 17 | } 18 | void implement(const Type* type) const override; 19 | virtual const Type* element() const override; 20 | virtual bool operator == (const Type*) const override; 21 | virtual int distance(const Type* type) const override; 22 | virtual std::ostream& print(std::ostream& os) const override; 23 | virtual Type* clone() const override; 24 | }; 25 | 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /src/type/Any_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ANY_TYPE_HPP 2 | #define ANY_TYPE_HPP 3 | 4 | #include "Pointer_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Any_type : public Pointer_type { 9 | public: 10 | Any_type(Environment& env, bool native = false); 11 | virtual ~Any_type() {} 12 | virtual const std::string getName() const override { return "any"; } 13 | virtual bool operator == (const Type*) const override; 14 | virtual bool callable() const override { return true; } 15 | virtual bool iterable() const override { return true; } 16 | virtual bool container() const override { return true; } 17 | virtual int distance(const Type* type) const override; 18 | virtual std::string class_name() const override; 19 | virtual std::ostream& print(std::ostream& os) const override; 20 | virtual Type* clone() const override; 21 | }; 22 | 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /src/analyzer/Result.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RESULT_HPP 2 | #define RESULT_HPP 3 | 4 | #include 5 | #include 6 | #include "error/Error.hpp" 7 | 8 | namespace ls { 9 | 10 | class Type; 11 | 12 | struct Result { 13 | bool analyzed = false; 14 | bool compilation_success = false; 15 | bool execution_success = false; 16 | std::vector errors; 17 | std::string program = ""; 18 | std::string value = ""; 19 | double parse_time = 0; 20 | double compilation_time = 0; 21 | double execution_time = 0; 22 | long operations = 0; 23 | int objects_created = 0; 24 | int objects_deleted = 0; 25 | int mpz_objects_created = 0; 26 | int mpz_objects_deleted = 0; 27 | std::string assembly; 28 | std::string pseudo_code; 29 | const Type* type = nullptr; 30 | #if COMPILER 31 | vm::ExceptionObj exception; 32 | #endif 33 | }; 34 | 35 | } 36 | 37 | #endif -------------------------------------------------------------------------------- /src/analyzer/instruction/Throw.hpp: -------------------------------------------------------------------------------- 1 | #ifndef THROW_HPP 2 | #define THROW_HPP 3 | 4 | #include "Instruction.hpp" 5 | 6 | namespace ls { 7 | 8 | class Throw : public Instruction { 9 | public: 10 | 11 | Token* token; 12 | std::unique_ptr expression; 13 | 14 | Throw(Environment& env, Token* token, std::unique_ptr = nullptr); 15 | 16 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 17 | virtual Location location() const override; 18 | 19 | virtual void pre_analyze(SemanticAnalyzer* analyzer) override; 20 | virtual void analyze(SemanticAnalyzer*, const Type* req_type) override; 21 | 22 | #if COMPILER 23 | virtual Compiler::value compile(Compiler&) const override; 24 | #endif 25 | 26 | virtual std::unique_ptr clone(Block* parent) const override; 27 | }; 28 | 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/type/Never_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Never_type.hpp" 2 | #include "Type.hpp" 3 | #include "../colors.h" 4 | 5 | namespace ls { 6 | 7 | Never_type::Never_type(Environment& env) : Any_type(env, true) {} 8 | 9 | bool Never_type::operator == (const Type* type) const { 10 | return dynamic_cast(type); 11 | } 12 | int Never_type::distance(const Type* type) const { 13 | if (not temporary and type->temporary) return -1; 14 | if (dynamic_cast(type->folded)) { return 0; } 15 | return 100000 + type->distance(this); 16 | } 17 | Json Never_type::json() const { 18 | return { 19 | { "name", "never" } 20 | }; 21 | } 22 | std::ostream& Never_type::print(std::ostream& os) const { 23 | os << BLUE_BOLD << "never" << END_COLOR; 24 | return os; 25 | } 26 | Type* Never_type::clone() const { 27 | return new Never_type { env }; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /src/type/Number_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NUMBER_TYPE_HPP 2 | #define NUMBER_TYPE_HPP 3 | 4 | #include "Pointer_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Number_type : public Type { 9 | public: 10 | Number_type(Environment& env); 11 | virtual int id() const override { return 3; } 12 | virtual const std::string getName() const override { return "number"; } 13 | virtual Json json() const override; 14 | virtual bool iterable() const override { return true; } 15 | virtual bool operator == (const Type*) const override; 16 | virtual int distance(const Type* type) const override; 17 | virtual std::string class_name() const override; 18 | #if COMPILER 19 | virtual llvm::Type* llvm(Compiler& c) const override; 20 | #endif 21 | virtual std::ostream& print(std::ostream& os) const override; 22 | virtual Type* clone() const override; 23 | }; 24 | 25 | } 26 | 27 | #endif -------------------------------------------------------------------------------- /test/operations.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.hpp" 2 | 3 | void Test::test_operations() { 4 | 5 | header("Operations"); 6 | code("2").operations(0); 7 | code("2 + 2").operations(1); 8 | code("2 * 3 + 4 * 5").operations(3); 9 | code("3 < 5").operations(1); 10 | code("[]").operations(1); 11 | code("[1, 2, 3]").operations(4); 12 | code("[1, 2, 3, 4, 5, 6, 7, 8, 9]").operations(10); 13 | code("[1][0]").operations(4); 14 | code("x -> x").operations(0); 15 | code("(x -> x + 1)(12)").operations(3); 16 | 17 | section("GMP operations"); 18 | code("12345m ** 12").operations(169); 19 | code("12345m ** 120").operations(1681); 20 | 21 | section("Operation limit exceeded"); 22 | code("while true {}").ops_limit(1000).exception(ls::vm::Exception::OPERATION_LIMIT_EXCEEDED); 23 | code("for ;; {}").ops_limit(1000).exception(ls::vm::Exception::OPERATION_LIMIT_EXCEEDED); 24 | } 25 | -------------------------------------------------------------------------------- /test/util.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.hpp" 2 | #include "../src/util/Util.hpp" 3 | 4 | void Test::test_utils() { 5 | 6 | header("Utils"); 7 | section("is_file_name"); 8 | 9 | ls::Util::is_file_name("Makefile"); // true 10 | ls::Util::is_file_name("12 + 5"); // false 11 | ls::Util::is_file_name("salut.leek"); // true 12 | ls::Util::is_file_name("hello.ls"); // true 13 | ls::Util::is_file_name("helloworld"); // false 14 | 15 | section("read_file_lines"); 16 | ls::Util::read_file_lines("Makefile"); 17 | 18 | section("replace_all"); 19 | std::string haystack = "bonjour"; 20 | std::string needle = "o"; 21 | std::string replacement = "_"; 22 | std::string res = ls::Util::replace_all(haystack, needle, replacement); 23 | assert(res == "b_nj_ur"); 24 | 25 | section("file_short_name"); 26 | assert(ls::Util::file_short_name("foo/bar/toto.txt") == "toto.txt"); 27 | } 28 | -------------------------------------------------------------------------------- /src/analyzer/value/ArrayFor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ARRAYFOR_HPP 2 | #define ARRAYFOR_HPP 3 | 4 | #include "Value.hpp" 5 | #include "../instruction/For.hpp" 6 | 7 | namespace ls { 8 | 9 | class ArrayFor : public Value { 10 | public: 11 | std::unique_ptr forr; 12 | 13 | ArrayFor(Environment& env); 14 | 15 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 16 | virtual Location location() const override; 17 | 18 | virtual void pre_analyze(SemanticAnalyzer*) override; 19 | virtual void analyze(SemanticAnalyzer*) override; 20 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 21 | 22 | #if COMPILER 23 | virtual Compiler::value compile(Compiler&) const override; 24 | #endif 25 | 26 | virtual std::unique_ptr clone(Block* parent) const override; 27 | }; 28 | 29 | } 30 | #endif // ARRAYFOR_H 31 | -------------------------------------------------------------------------------- /src/analyzer/value/Phi.cpp: -------------------------------------------------------------------------------- 1 | #include "Phi.hpp" 2 | #include "../value/Block.hpp" 3 | #include "../semantic/Variable.hpp" 4 | #include "../semantic/SemanticAnalyzer.hpp" 5 | #include "../semantic/FunctionVersion.hpp" 6 | 7 | namespace ls { 8 | 9 | Phi::Phi(Environment& env, Variable* variable, Block* block1, Variable* variable1, Block* block2, Variable* variable2) : variable(variable), block1(block1), variable1(variable1), block2(block2) 10 | , variable2(variable2) 11 | #if COMPILER 12 | , value1(env), value2(env), phi_node(env) 13 | #endif 14 | {} 15 | 16 | Phi::Phi(Environment& env, Variable* variable, Section* section1, Variable* variable1, Section* section2, Variable* variable2) : variable(variable), section1(section1), variable1(variable1), section2(section2) 17 | , variable2(variable2) 18 | #if COMPILER 19 | , value1(env), value2(env), phi_node(env) 20 | #endif 21 | {} 22 | 23 | } -------------------------------------------------------------------------------- /src/standard/class/SetSTD.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VM_STANDARD_SETSTD_HPP_ 2 | #define VM_STANDARD_SETSTD_HPP_ 3 | 4 | #include "../Module.hpp" 5 | 6 | namespace ls { 7 | 8 | class SetSTD : public Module { 9 | public: 10 | SetSTD(Environment& env); 11 | 12 | #if COMPILER 13 | 14 | static Compiler::value new_(Compiler& c, std::vector args, int); 15 | 16 | static Compiler::value in_any(Compiler& c, std::vector args, int); 17 | static Compiler::value set_add_eq(Compiler& c, std::vector args, int); 18 | 19 | static Compiler::value insert_any(Compiler& c, std::vector args, int); 20 | static Compiler::value insert_real(Compiler& c, std::vector args, int); 21 | static Compiler::value insert_int(Compiler& c, std::vector args, int); 22 | 23 | #endif 24 | }; 25 | 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/type/Meta_not_void_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef META_NOT_VOID_TYPE_HPP 2 | #define META_NOT_VOID_TYPE_HPP 3 | 4 | #include "Type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Meta_not_void_type : public Type { 9 | public: 10 | const Type* type; 11 | Meta_not_void_type(const Type* type) : Type(type->env), type(type) {} 12 | virtual int id() const override { return 0; } 13 | virtual const std::string getName() const override { return "meta_not_void"; } 14 | virtual Json json() const override; 15 | virtual bool operator == (const Type*) const override; 16 | virtual int distance(const Type* type) const override; 17 | #if COMPILER 18 | virtual llvm::Type* llvm(Compiler& c) const override; 19 | #endif 20 | virtual std::string class_name() const override; 21 | virtual std::ostream& print(std::ostream& os) const override; 22 | virtual Type* clone() const override; 23 | }; 24 | 25 | } 26 | 27 | #endif -------------------------------------------------------------------------------- /src/type/Object_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OBJECT_TYPE_HPP 2 | #define OBJECT_TYPE_HPP 3 | 4 | #include "Pointer_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Object_type : public Pointer_type { 9 | public: 10 | Object_type(Environment& env, bool native = false); 11 | virtual int id() const override { return 10; } 12 | virtual const std::string getName() const override { return "object"; } 13 | virtual Json json() const override; 14 | virtual bool iterable() const override { return false; } // TODO not iterable for now 15 | virtual bool container() const override { return true; } 16 | virtual bool operator == (const Type*) const override; 17 | virtual int distance(const Type* type) const override; 18 | virtual std::string class_name() const override; 19 | virtual std::ostream& print(std::ostream& os) const override; 20 | virtual Type* clone() const override; 21 | }; 22 | 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /src/type/Meta_add_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef META_ADD_TYPE_HPP 2 | #define META_ADD_TYPE_HPP 3 | 4 | #include "Type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Meta_add_type : public Type { 9 | public: 10 | const Type* t1; 11 | const Type* t2; 12 | Meta_add_type(const Type* t1, const Type* t2) : Type(t1->env), t1(t1), t2(t2) {} 13 | virtual int id() const override { return 0; } 14 | virtual const std::string getName() const override { return "meta_add"; } 15 | virtual Json json() const override; 16 | virtual bool operator == (const Type*) const override; 17 | virtual int distance(const Type* type) const override; 18 | #if COMPILER 19 | virtual llvm::Type* llvm(Compiler& c) const override; 20 | #endif 21 | virtual std::string class_name() const override; 22 | virtual std::ostream& print(std::ostream& os) const override; 23 | virtual Type* clone() const override; 24 | }; 25 | 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /src/type/Meta_mul_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef META_MUL_TYPE_HPP 2 | #define META_MUL_TYPE_HPP 3 | 4 | #include "Type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Meta_mul_type : public Type { 9 | public: 10 | const Type* t1; 11 | const Type* t2; 12 | Meta_mul_type(const Type* t1, const Type* t2) : Type(t1->env), t1(t1), t2(t2) {} 13 | virtual int id() const override { return 0; } 14 | virtual const std::string getName() const override { return "meta_mul"; } 15 | virtual Json json() const override; 16 | virtual bool operator == (const Type*) const override; 17 | virtual int distance(const Type* type) const override; 18 | #if COMPILER 19 | virtual llvm::Type* llvm(Compiler& c) const override; 20 | #endif 21 | virtual std::string class_name() const override; 22 | virtual std::ostream& print(std::ostream& os) const override; 23 | virtual Type* clone() const override; 24 | }; 25 | 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /src/type/Meta_temporary_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef META_TEMPORARY_TYPE_HPP 2 | #define META_TEMPORARY_TYPE_HPP 3 | 4 | #include "Type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Meta_temporary_type : public Type { 9 | public: 10 | const Type* type; 11 | Meta_temporary_type(const Type* type) : Type(type->env), type(type) {} 12 | virtual int id() const override { return 0; } 13 | virtual const std::string getName() const override { return "meta_temporary"; } 14 | virtual Json json() const override; 15 | virtual bool operator == (const Type*) const override; 16 | virtual int distance(const Type* type) const override; 17 | #if COMPILER 18 | virtual llvm::Type* llvm(Compiler& c) const override; 19 | #endif 20 | virtual std::string class_name() const override; 21 | virtual std::ostream& print(std::ostream& os) const override; 22 | virtual Type* clone() const override; 23 | }; 24 | 25 | } 26 | 27 | #endif -------------------------------------------------------------------------------- /benchmark/code/cubic_permutations/cubic_permutations.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | long code(int p) { 9 | std::map groups; 10 | std::map first; 11 | int i = p + 1; 12 | 13 | while (i++) { 14 | 15 | std::string n = std::to_string(std::pow(i, 3)); 16 | std::string ns = n; 17 | std::sort(ns.begin(), ns.end()); 18 | 19 | if (groups.find(ns) != groups.end()) { 20 | groups[ns]++; 21 | if (groups[ns] == 5) { 22 | return std::stol(first[ns]); 23 | } 24 | } else { 25 | groups.insert({ns, 1}); 26 | first.insert({ns, n}); 27 | } 28 | } 29 | return 0; 30 | } 31 | 32 | int main() { 33 | long s = 0; 34 | for (int i = 0; i < 60; ++i) { 35 | s += code(i); 36 | } 37 | std::cout << s << std::endl; 38 | return s; 39 | } 40 | -------------------------------------------------------------------------------- /src/type/Meta_add_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Meta_add_type.hpp" 2 | #include "../colors.h" 3 | #if COMPILER 4 | #include "../compiler/Compiler.hpp" 5 | #endif 6 | 7 | namespace ls { 8 | 9 | bool Meta_add_type::operator == (const Type* type) const { 10 | return false; 11 | } 12 | int Meta_add_type::distance(const Type* type) const { 13 | return -1; 14 | } 15 | #if COMPILER 16 | llvm::Type* Meta_add_type::llvm(Compiler& c) const { 17 | return llvm::Type::getVoidTy(c.getContext()); 18 | } 19 | #endif 20 | std::string Meta_add_type::class_name() const { 21 | return ""; 22 | } 23 | Json Meta_add_type::json() const { 24 | return { 25 | t1->json(), 26 | t2->json() 27 | }; 28 | } 29 | std::ostream& Meta_add_type::print(std::ostream& os) const { 30 | os << C_GREY << t1 << " | " << t2 << END_COLOR; 31 | return os; 32 | } 33 | Type* Meta_add_type::clone() const { 34 | return new Meta_add_type(t1, t2); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/type/Meta_mul_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Meta_mul_type.hpp" 2 | #include "../colors.h" 3 | #if COMPILER 4 | #include "../compiler/Compiler.hpp" 5 | #endif 6 | 7 | namespace ls { 8 | 9 | bool Meta_mul_type::operator == (const Type* type) const { 10 | return false; 11 | } 12 | int Meta_mul_type::distance(const Type* type) const { 13 | return -1; 14 | } 15 | #if COMPILER 16 | llvm::Type* Meta_mul_type::llvm(Compiler& c) const { 17 | return llvm::Type::getVoidTy(c.getContext()); 18 | } 19 | #endif 20 | std::string Meta_mul_type::class_name() const { 21 | return ""; 22 | } 23 | Json Meta_mul_type::json() const { 24 | return { 25 | t1->json(), 26 | t2->json() 27 | }; 28 | } 29 | std::ostream& Meta_mul_type::print(std::ostream& os) const { 30 | os << C_GREY << t1 << " * " << t2 << END_COLOR; 31 | return os; 32 | } 33 | Type* Meta_mul_type::clone() const { 34 | return new Meta_mul_type(t1, t2); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/type/Meta_concat_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef META_CONCAT_TYPE_HPP 2 | #define META_CONCAT_TYPE_HPP 3 | 4 | #include "Type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Meta_concat_type : public Type { 9 | public: 10 | const Type* t1; 11 | const Type* t2; 12 | Meta_concat_type(const Type* t1, const Type* t2) : Type(t1->env), t1(t1), t2(t2) {} 13 | virtual int id() const override { return 0; } 14 | virtual const std::string getName() const override { return "meta_concat"; } 15 | virtual Json json() const override; 16 | virtual bool operator == (const Type*) const override; 17 | virtual int distance(const Type* type) const override; 18 | #if COMPILER 19 | virtual llvm::Type* llvm(Compiler& c) const override; 20 | #endif 21 | virtual std::string class_name() const override; 22 | virtual std::ostream& print(std::ostream& os) const override; 23 | virtual Type* clone() const override; 24 | }; 25 | 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /src/analyzer/value/Interval.hpp: -------------------------------------------------------------------------------- 1 | #ifndef INTERVAL_HPP 2 | #define INTERVAL_HPP 3 | 4 | #include 5 | #include 6 | #include "Value.hpp" 7 | #include "../lexical/Token.hpp" 8 | 9 | namespace ls { 10 | 11 | class Interval : public Value { 12 | public: 13 | 14 | Token* opening_bracket; 15 | Token* closing_bracket; 16 | std::unique_ptr start; 17 | std::unique_ptr end; 18 | 19 | Interval(Environment& env); 20 | 21 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 22 | virtual Location location() const override; 23 | 24 | virtual void pre_analyze(SemanticAnalyzer*) override; 25 | virtual void analyze(SemanticAnalyzer*) override; 26 | 27 | #if COMPILER 28 | virtual Compiler::value compile(Compiler&) const override; 29 | #endif 30 | 31 | virtual std::unique_ptr clone(Block* parent) const override; 32 | }; 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/analyzer/value/Set.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SET_HPP 2 | #define SET_HPP 3 | 4 | #include 5 | #include "Value.hpp" 6 | 7 | namespace ls { 8 | 9 | class Set : public Value { 10 | public: 11 | std::vector> expressions; 12 | 13 | Set(Environment& env); 14 | 15 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 16 | virtual Location location() const override; 17 | virtual void pre_analyze(SemanticAnalyzer*) override; 18 | virtual void analyze(SemanticAnalyzer*) override; 19 | virtual bool will_store(SemanticAnalyzer* analyzer, const Type* type) override; 20 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 21 | 22 | #if COMPILER 23 | virtual Compiler::value compile(Compiler&) const override; 24 | #endif 25 | 26 | virtual std::unique_ptr clone(Block* parent) const override; 27 | }; 28 | 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/type/Long_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LONG_TYPE_HPP 2 | #define LONG_TYPE_HPP 3 | 4 | #include "Number_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Long_type : public Number_type { 9 | public: 10 | Long_type(Environment& env) : Number_type(env) {} 11 | virtual const std::string getName() const override { return "long"; } 12 | virtual Json json() const override; 13 | virtual const Type* key() const override; 14 | virtual const Type* element() const override; 15 | virtual const Type* iterator() const override; 16 | virtual bool operator == (const Type*) const override; 17 | virtual int distance(const Type* type) const override; 18 | #if COMPILER 19 | virtual llvm::Type* llvm(Compiler& c) const override; 20 | #endif 21 | virtual std::string class_name() const override; 22 | virtual std::ostream& print(std::ostream& os) const override; 23 | virtual Type* clone() const override; 24 | }; 25 | 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /src/analyzer/value/PostfixExpression.hpp: -------------------------------------------------------------------------------- 1 | #ifndef POSTFIXEXPRESSION_HPP 2 | #define POSTFIXEXPRESSION_HPP 3 | 4 | #include "Expression.hpp" 5 | #include "LeftValue.hpp" 6 | #include "Value.hpp" 7 | 8 | namespace ls { 9 | 10 | class PostfixExpression : public Value { 11 | public: 12 | 13 | std::unique_ptr expression; 14 | std::shared_ptr operatorr; 15 | bool return_value; 16 | 17 | PostfixExpression(Environment& env); 18 | 19 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 20 | virtual Location location() const override; 21 | 22 | virtual void pre_analyze(SemanticAnalyzer*) override; 23 | virtual void analyze(SemanticAnalyzer*) override; 24 | 25 | #if COMPILER 26 | virtual Compiler::value compile(Compiler&) const override; 27 | #endif 28 | 29 | virtual std::unique_ptr clone(Block* parent) const override; 30 | }; 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/type/Meta_not_temporary_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef META_NOT_TEMPORARY_TYPE_HPP 2 | #define META_NOT_TEMPORARY_TYPE_HPP 3 | 4 | #include "Type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Meta_not_temporary_type : public Type { 9 | public: 10 | const Type* type; 11 | Meta_not_temporary_type(const Type* type) : Type(type->env), type(type) {} 12 | virtual int id() const override { return 0; } 13 | virtual const std::string getName() const override { return "meta_not_temporary"; } 14 | virtual Json json() const override; 15 | virtual bool operator == (const Type*) const override; 16 | virtual int distance(const Type* type) const override; 17 | #if COMPILER 18 | virtual llvm::Type* llvm(Compiler& c) const override; 19 | #endif 20 | virtual std::string class_name() const override; 21 | virtual std::ostream& print(std::ostream& os) const override; 22 | virtual Type* clone() const override; 23 | }; 24 | 25 | } 26 | 27 | #endif -------------------------------------------------------------------------------- /src/type/Integer_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef INTEGER_TYPE_HPP 2 | #define INTEGER_TYPE_HPP 3 | 4 | #include "Number_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Integer_type : public Number_type { 9 | public: 10 | Integer_type(Environment& env) : Number_type(env) {} 11 | virtual const std::string getName() const override { return "int"; } 12 | virtual Json json() const override; 13 | virtual const Type* key() const override; 14 | virtual const Type* element() const override; 15 | virtual const Type* iterator() const override; 16 | virtual bool operator == (const Type*) const override; 17 | virtual int distance(const Type* type) const override; 18 | #if COMPILER 19 | virtual llvm::Type* llvm(Compiler& c) const override; 20 | #endif 21 | virtual std::string class_name() const override; 22 | virtual std::ostream& print(std::ostream&) const override; 23 | virtual Type* clone() const override; 24 | }; 25 | 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /src/type/Meta_not_void_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Meta_not_void_type.hpp" 2 | #include "../colors.h" 3 | #if COMPILER 4 | #include "../compiler/Compiler.hpp" 5 | #endif 6 | 7 | namespace ls { 8 | 9 | bool Meta_not_void_type::operator == (const Type* type) const { 10 | return false; 11 | } 12 | int Meta_not_void_type::distance(const Type* type) const { 13 | return -1; 14 | } 15 | #if COMPILER 16 | llvm::Type* Meta_not_void_type::llvm(Compiler& c) const { 17 | return llvm::Type::getVoidTy(c.getContext()); 18 | } 19 | #endif 20 | std::string Meta_not_void_type::class_name() const { 21 | return ""; 22 | } 23 | Json Meta_not_void_type::json() const { 24 | return type->json(); 25 | } 26 | std::ostream& Meta_not_void_type::print(std::ostream& os) const { 27 | os << C_GREY << "!void(" << type << ")" << END_COLOR; 28 | return os; 29 | } 30 | Type* Meta_not_void_type::clone() const { 31 | return new Meta_not_void_type(type); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /test/code/euler/pe023.leek: -------------------------------------------------------------------------------- 1 | function isAbundant(n) { 2 | var sum = 0; 3 | var half = n \ 2; 4 | for (var i = 1; i <= half; ++i) 5 | if (n % i == 0) { 6 | sum += i 7 | } 8 | return sum > n 9 | } 10 | 11 | let N = 28123 12 | 13 | var numbers = [].fill(0, N) 14 | var abundant = [].fill(false, N) 15 | var canBeWritten = [].fill(false, N) 16 | 17 | for (var i = 0; i < N; ++i) { 18 | numbers[i] = i + 1 19 | abundant[i] = isAbundant(i + 1) 20 | canBeWritten[i] = false 21 | } 22 | 23 | for (var i = 0; i < N; ++i) { 24 | if (abundant[i]) { 25 | for (var j = 0; j < N; ++j) { 26 | if (abundant[j]) { 27 | var sum = numbers[i] + numbers[j]; 28 | if (sum <= N) canBeWritten[sum - 1] = true; 29 | } 30 | } 31 | } 32 | } 33 | 34 | var sum = 0; 35 | for (var i = 0; i < N; ++i) { 36 | if (!canBeWritten[i]) sum += (i + 1); 37 | } 38 | 39 | sum -------------------------------------------------------------------------------- /src/type/Meta_element_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef META_ELEMENT_TYPE_HPP 2 | #define META_ELEMENT_TYPE_HPP 3 | 4 | #include "Any_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Meta_element_type : public Any_type { 9 | public: 10 | const Type* type; 11 | Meta_element_type(const Type* type) : Any_type(type->env), type(type) { 12 | placeholder = true; 13 | } 14 | virtual int id() const override { return 0; } 15 | virtual const std::string getName() const override { return "meta_element"; } 16 | virtual Json json() const override; 17 | virtual bool operator == (const Type*) const override; 18 | virtual int distance(const Type* type) const override; 19 | #if COMPILER 20 | virtual llvm::Type* llvm(Compiler& c) const override; 21 | #endif 22 | virtual std::string class_name() const override; 23 | virtual std::ostream& print(std::ostream& os) const override; 24 | virtual Type* clone() const override; 25 | }; 26 | 27 | } 28 | 29 | #endif -------------------------------------------------------------------------------- /src/type/Meta_concat_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Meta_concat_type.hpp" 2 | #include "../colors.h" 3 | #if COMPILER 4 | #include "../compiler/Compiler.hpp" 5 | #endif 6 | 7 | namespace ls { 8 | 9 | bool Meta_concat_type::operator == (const Type* type) const { 10 | return false; 11 | } 12 | int Meta_concat_type::distance(const Type* type) const { 13 | return -1; 14 | } 15 | #if COMPILER 16 | llvm::Type* Meta_concat_type::llvm(Compiler& c) const { 17 | return llvm::Type::getVoidTy(c.getContext()); 18 | } 19 | #endif 20 | std::string Meta_concat_type::class_name() const { 21 | return ""; 22 | } 23 | Json Meta_concat_type::json() const { 24 | return { 25 | t1->json(), 26 | t2->json() 27 | }; 28 | } 29 | std::ostream& Meta_concat_type::print(std::ostream& os) const { 30 | os << C_GREY << t1 << " + " << t2 << END_COLOR; 31 | return os; 32 | } 33 | Type* Meta_concat_type::clone() const { 34 | return new Meta_concat_type(t1, t2); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/type/Meta_temporary_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Meta_temporary_type.hpp" 2 | #include "../colors.h" 3 | #if COMPILER 4 | #include "../compiler/Compiler.hpp" 5 | #endif 6 | 7 | namespace ls { 8 | 9 | bool Meta_temporary_type::operator == (const Type* type) const { 10 | return false; 11 | } 12 | int Meta_temporary_type::distance(const Type* type) const { 13 | return -1; 14 | } 15 | #if COMPILER 16 | llvm::Type* Meta_temporary_type::llvm(Compiler& c) const { 17 | return llvm::Type::getVoidTy(c.getContext()); 18 | } 19 | #endif 20 | std::string Meta_temporary_type::class_name() const { 21 | return ""; 22 | } 23 | Json Meta_temporary_type::json() const { 24 | return type->json(); 25 | } 26 | std::ostream& Meta_temporary_type::print(std::ostream& os) const { 27 | os << C_GREY << "tmp(" << type << ")" << END_COLOR; 28 | return os; 29 | } 30 | Type* Meta_temporary_type::clone() const { 31 | return new Meta_temporary_type(type); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/analyzer/instruction/Instruction.cpp: -------------------------------------------------------------------------------- 1 | #include "Instruction.hpp" 2 | #include "../semantic/SemanticAnalyzer.hpp" 3 | 4 | namespace ls { 5 | 6 | Instruction::Instruction(Environment& env) : type(env.void_), return_type(env.void_) {} 7 | 8 | void Instruction::set_end_section(Section*) {} 9 | 10 | void Instruction::pre_analyze(SemanticAnalyzer*) {} 11 | 12 | void Instruction::analyze(SemanticAnalyzer* analyzer) { 13 | analyze(analyzer, analyzer->env.any); 14 | } 15 | 16 | Completion Instruction::autocomplete(SemanticAnalyzer& analyzer, size_t position) const { 17 | return { analyzer.env }; 18 | } 19 | 20 | Hover Instruction::hover(SemanticAnalyzer& analyzer, size_t position) const { 21 | return { type, location() }; 22 | } 23 | 24 | #if COMPILER 25 | void Instruction::compile_end(Compiler& c) const {} 26 | #endif 27 | 28 | std::string Instruction::tabs(int indent) const { 29 | return std::string(indent * 4, ' '); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/analyzer/value/Boolean.cpp: -------------------------------------------------------------------------------- 1 | #include "Boolean.hpp" 2 | #include "../../type/Type.hpp" 3 | #include "../semantic/SemanticAnalyzer.hpp" 4 | 5 | namespace ls { 6 | 7 | Boolean::Boolean(Environment& env, Token* token) : Value(env), token(token) { 8 | this->value = token->type == TokenType::TRUE; 9 | type = env.boolean; 10 | constant = true; 11 | } 12 | 13 | void Boolean::print(std::ostream& os, int, PrintOptions options) const { 14 | os << (value ? "true" : "false"); 15 | if (options.debug) { 16 | os << " " << type; 17 | } 18 | } 19 | 20 | Location Boolean::location() const { 21 | return token->location; 22 | } 23 | 24 | #if COMPILER 25 | Compiler::value Boolean::compile(Compiler& c) const { 26 | return c.new_bool(value); 27 | } 28 | #endif 29 | 30 | std::unique_ptr Boolean::clone(Block* parent) const { 31 | auto b = std::make_unique(type->env, token); 32 | b->value = value; 33 | return b; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/type/Void_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VOID_TYPE_HPP 2 | #define VOID_TYPE_HPP 3 | 4 | #include "Type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Void_type : public Type { 9 | public: 10 | Void_type(Environment& env) : Type(env) {} 11 | virtual int id() const override { return 0; } 12 | virtual const std::string getName() const override { return "void"; } 13 | virtual Json json() const override; 14 | virtual const Type* element() const override; 15 | virtual const Type* key() const override; 16 | virtual const Type* return_type() const override; 17 | virtual bool operator == (const Type*) const override; 18 | virtual int distance(const Type* type) const override; 19 | #if COMPILER 20 | virtual llvm::Type* llvm(Compiler& c) const override; 21 | #endif 22 | virtual std::string class_name() const override; 23 | virtual std::ostream& print(std::ostream& os) const override; 24 | virtual Type* clone() const override; 25 | }; 26 | 27 | } 28 | 29 | #endif -------------------------------------------------------------------------------- /leekscript.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "leekscript", 5 | "type": "executable", 6 | "sources": [ 7 | ' 5 | #include "../../constants.h" 6 | #if COMPILER 7 | #include "../../compiler/Compiler.hpp" 8 | #endif 9 | 10 | namespace ls { 11 | 12 | class Variable; 13 | class Block; 14 | class SemanticAnalyzer; 15 | class Environment; 16 | class Section; 17 | 18 | class Phi { 19 | public: 20 | Variable* variable; 21 | Block* block1; 22 | Section* section1; 23 | Variable* variable1; 24 | Block* block2; 25 | Section* section2; 26 | Variable* variable2; 27 | bool active = true; 28 | #if COMPILER 29 | Compiler::value value1; 30 | Compiler::value value2; 31 | Compiler::value phi_node; 32 | #endif 33 | 34 | Phi(Environment& env, Variable* variable, Block* block1, Variable* value1, Block* block2, Variable* value2); 35 | Phi(Environment& env, Variable* variable, Section* section1, Variable* value1, Section* section2, Variable* value2); 36 | }; 37 | 38 | } 39 | 40 | #endif -------------------------------------------------------------------------------- /src/analyzer/instruction/Return.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RETURN_HPP 2 | #define RETURN_HPP 3 | 4 | #include "Instruction.hpp" 5 | 6 | namespace ls { 7 | 8 | class Return : public Instruction { 9 | public: 10 | 11 | Token* token = nullptr; 12 | std::unique_ptr expression; 13 | 14 | Return(Environment& env, Token* token, std::unique_ptr = nullptr); 15 | 16 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 17 | virtual Location location() const override; 18 | 19 | virtual void pre_analyze(SemanticAnalyzer* analyzer) override; 20 | virtual void analyze(SemanticAnalyzer*, const Type* req_type) override; 21 | 22 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 23 | 24 | #if COMPILER 25 | virtual Compiler::value compile(Compiler&) const override; 26 | #endif 27 | 28 | virtual std::unique_ptr clone(Block* parent) const override; 29 | }; 30 | 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/analyzer/lexical/LexicalAnalyzer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LEXICALanalyzer_H_ 2 | #define LEXICALanalyzer_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Token.hpp" 9 | #include "../resolver/File.hpp" 10 | 11 | namespace ls { 12 | 13 | enum class LetterType { 14 | LETTER, NUMBER, QUOTE, DOUBLE_QUOTE, WHITE, OTHER 15 | }; 16 | 17 | class LexicalAnalyzer { 18 | public: 19 | 20 | static std::unordered_set ignored_case_legacy; 21 | 22 | File* file; 23 | std::unordered_map token_map; 24 | 25 | LexicalAnalyzer(); 26 | 27 | LetterType getLetterType(unsigned char c, unsigned char nc); 28 | bool isToken(const std::string& word); 29 | TokenType getTokenType(const std::string& word, TokenType by_default); 30 | std::vector parseTokens(const std::string& code); 31 | 32 | std::vector analyze(File* file); 33 | }; 34 | 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/analyzer/semantic/Callable.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CALLABLE_HPP_ 2 | #define CALLABLE_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "CallableVersionTemplate.hpp" 8 | 9 | namespace ls { 10 | 11 | class Value; 12 | class SemanticAnalyzer; 13 | class Type; 14 | 15 | class Callable { 16 | public: 17 | std::vector versions; 18 | 19 | Callable() {} 20 | Callable(std::initializer_list versions) : versions(versions) {} 21 | // Callable(std::initializer_list> versions) : versions(versions) {} 22 | 23 | const CallableVersion* resolve(SemanticAnalyzer* analyzer, std::vector arguments) const; 24 | bool is_compatible(int argument_count); 25 | void add_version(CallableVersionTemplate version); 26 | }; 27 | 28 | } 29 | 30 | namespace std { 31 | std::ostream& operator << (std::ostream&, const ls::Callable*); 32 | } 33 | 34 | #endif -------------------------------------------------------------------------------- /src/type/Template_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TEMPLATE_TYPE_HPP 2 | #define TEMPLATE_TYPE_HPP 3 | 4 | #include "Any_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Type; 9 | 10 | class Template_type : public Type { 11 | std::string _name; 12 | public: 13 | const Type* _implementation = nullptr; 14 | virtual void reset() const override; 15 | Template_type(Environment& env, const std::string name); 16 | virtual Json json() const override; 17 | virtual void implement(const Type* type) const override; 18 | virtual bool operator == (const Type*) const override; 19 | virtual int distance(const Type* type) const override; 20 | #if COMPILER 21 | virtual llvm::Type* llvm(Compiler& c) const override; 22 | #endif 23 | virtual std::string class_name() const override; 24 | virtual const std::string getName() const override; 25 | virtual std::ostream& print(std::ostream& os) const override; 26 | virtual Type* clone() const override; 27 | 28 | }; 29 | 30 | } 31 | 32 | #endif -------------------------------------------------------------------------------- /benchmark/code/cubic_permutations/cubic_permutations.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | class cubic_permutations { 4 | 5 | public static void main(String[] args) { 6 | long s = 0; 7 | for (int i = 0; i < 60; ++i) { 8 | s += code(i); 9 | } 10 | System.out.println(s); 11 | } 12 | 13 | public static long code(int p) { 14 | Map groups = new TreeMap(); 15 | Map first = new TreeMap(); 16 | int i = 1 + p; 17 | 18 | while (i++ > 0) { 19 | 20 | String n = "" + (long) Math.pow(i, 3); 21 | char[] ar = n.toCharArray(); 22 | Arrays.sort(ar); 23 | String ns = String.valueOf(ar); 24 | 25 | if (groups.containsKey(ns)) { 26 | groups.put(ns, groups.get(ns) + 1); 27 | if (groups.get(ns) == 5) { 28 | return Long.parseLong(first.get(ns)); 29 | } 30 | } else { 31 | groups.put(ns, 1); 32 | first.put(ns, n); 33 | } 34 | } 35 | return 0; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/analyzer/value/AbsoluteValue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ABSOLUTEVALUE_HPP 2 | #define ABSOLUTEVALUE_HPP 3 | 4 | #include 5 | #include "Value.hpp" 6 | #include "../lexical/Token.hpp" 7 | 8 | namespace ls { 9 | 10 | class AbsoluteValue : public Value { 11 | public: 12 | 13 | std::unique_ptr expression; 14 | Token* open_pipe; 15 | Token* close_pipe; 16 | 17 | AbsoluteValue(Environment& env); 18 | 19 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 20 | virtual Location location() const override; 21 | 22 | virtual void pre_analyze(SemanticAnalyzer*) override; 23 | virtual void analyze(SemanticAnalyzer*) override; 24 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 25 | 26 | #if COMPILER 27 | virtual Compiler::value compile(Compiler&) const override; 28 | #endif 29 | 30 | virtual std::unique_ptr clone(Block* parent) const override; 31 | }; 32 | 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/type/Meta_element_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Meta_element_type.hpp" 2 | #include "../colors.h" 3 | #if COMPILER 4 | #include "../compiler/Compiler.hpp" 5 | #endif 6 | 7 | namespace ls { 8 | 9 | bool Meta_element_type::operator == (const Type* type) const { 10 | return this->type == type; 11 | } 12 | int Meta_element_type::distance(const Type* type) const { 13 | return 0; 14 | } 15 | #if COMPILER 16 | llvm::Type* Meta_element_type::llvm(Compiler& c) const { 17 | return llvm::Type::getVoidTy(c.getContext()); 18 | } 19 | #endif 20 | std::string Meta_element_type::class_name() const { 21 | return ""; 22 | } 23 | Json Meta_element_type::json() const { 24 | return { 25 | { "name", "element" }, 26 | { "element", type->json() } 27 | }; 28 | } 29 | std::ostream& Meta_element_type::print(std::ostream& os) const { 30 | os << type << ".element"; 31 | return os; 32 | } 33 | Type* Meta_element_type::clone() const { 34 | return new Meta_element_type(type); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/type/Meta_not_temporary_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Meta_not_temporary_type.hpp" 2 | #include "../colors.h" 3 | #if COMPILER 4 | #include "../compiler/Compiler.hpp" 5 | #endif 6 | 7 | namespace ls { 8 | 9 | bool Meta_not_temporary_type::operator == (const Type* type) const { 10 | return false; 11 | } 12 | int Meta_not_temporary_type::distance(const Type* type) const { 13 | return -1; 14 | } 15 | #if COMPILER 16 | llvm::Type* Meta_not_temporary_type::llvm(Compiler& c) const { 17 | return llvm::Type::getVoidTy(c.getContext()); 18 | } 19 | #endif 20 | std::string Meta_not_temporary_type::class_name() const { 21 | return ""; 22 | } 23 | Json Meta_not_temporary_type::json() const { 24 | return type->json(); 25 | } 26 | std::ostream& Meta_not_temporary_type::print(std::ostream& os) const { 27 | os << C_GREY << "not_tmp(" << type << ")" << END_COLOR; 28 | return os; 29 | } 30 | Type* Meta_not_temporary_type::clone() const { 31 | return new Meta_not_temporary_type(type); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/type/String_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef STRING_TYPE_HPP 2 | #define STRING_TYPE_HPP 3 | 4 | #include "Pointer_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class String_type : public Pointer_type { 9 | public: 10 | String_type(Environment& env); 11 | virtual int id() const override { return 4; } 12 | virtual const std::string getName() const override { return "string"; } 13 | virtual Json json() const override; 14 | virtual bool iterable() const override { return true; } 15 | virtual const Type* iterator() const override; 16 | virtual const Type* key() const override; 17 | virtual const Type* element() const override; 18 | virtual bool container() const override { return true; } 19 | virtual bool operator == (const Type*) const override; 20 | virtual int distance(const Type* type) const override; 21 | virtual std::string class_name() const override; 22 | virtual std::ostream& print(std::ostream& os) const override; 23 | virtual Type* clone() const override; 24 | }; 25 | 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /src/analyzer/value/Map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAP_HPP 2 | #define MAP_HPP 3 | 4 | #include 5 | #include 6 | #include "Value.hpp" 7 | #include "../lexical/Token.hpp" 8 | 9 | namespace ls { 10 | 11 | class Map : public Value { 12 | public: 13 | Token* opening_bracket; 14 | Token* closing_bracket; 15 | std::vector> keys; 16 | std::vector> values; 17 | 18 | Map(Environment& env); 19 | 20 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 21 | virtual Location location() const override; 22 | 23 | virtual void pre_analyze(SemanticAnalyzer*) override; 24 | virtual void analyze(SemanticAnalyzer*) override; 25 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 26 | 27 | #if COMPILER 28 | virtual Compiler::value compile(Compiler&) const override; 29 | #endif 30 | 31 | virtual std::unique_ptr clone(Block* parent) const override; 32 | }; 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/analyzer/lexical/Token.cpp: -------------------------------------------------------------------------------- 1 | #include "Token.hpp" 2 | #include 3 | #include "LexicalAnalyzer.hpp" 4 | #include "../../util/Util.hpp" 5 | 6 | namespace ls { 7 | 8 | Token::Token(TokenType type, File* file, size_t raw, size_t line, size_t character, const std::string& content) 9 | : type(type), content(content), location(file, {line, character - content.size() - 1, raw - content.size() - 1}, {line, character - 2, raw - 2}) { 10 | 11 | // TODO legacy only 12 | auto word_lower = Util::tolower(content); 13 | bool ignore_case = LexicalAnalyzer::ignored_case_legacy.find(word_lower) != LexicalAnalyzer::ignored_case_legacy.end(); 14 | if (ignore_case) { 15 | this->content = word_lower; 16 | } 17 | 18 | if (type == TokenType::STRING) { 19 | this->location.start.column--; 20 | this->location.start.raw--; 21 | this->location.end.raw++; 22 | this->location.end.column++; 23 | this->size = content.size() + 2; 24 | } else { 25 | this->size = content.size(); 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/analyzer/resolver/FileResolver.cpp: -------------------------------------------------------------------------------- 1 | #include "FileResolver.hpp" 2 | #include 3 | #include "../../util/Util.hpp" 4 | #include 5 | #include "../Program.hpp" 6 | 7 | namespace ls { 8 | 9 | // static std::unordered_map file_cache; 10 | 11 | File* FileResolver::create(std::string path, Program* program) const { 12 | auto fspath = std::filesystem::path(path); 13 | return /* file_cache[path] = */ new File(path, program->code, FileContext(fspath.parent_path()), program); 14 | } 15 | 16 | File* FileResolver::resolve(std::string path, FileContext context) const { 17 | auto resolvedPath = (context.folder / path).lexically_normal(); 18 | // auto i = file_cache.find(resolvedPath); 19 | // if (i != file_cache.end()) { 20 | // return i->second; 21 | // } 22 | auto code = Util::read_file(resolvedPath); 23 | auto newContext = FileContext(resolvedPath.parent_path()); 24 | return /* file_cache[path] = */ new File(path, code, newContext, nullptr); 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /src/analyzer/semantic/Callable.cpp: -------------------------------------------------------------------------------- 1 | #include "Callable.hpp" 2 | #include "../semantic/SemanticAnalyzer.hpp" 3 | #include "../../standard/Module.hpp" 4 | #include "CallableVersion.hpp" 5 | #include "../../type/Type.hpp" 6 | 7 | namespace ls { 8 | 9 | void Callable::add_version(CallableVersionTemplate v) { 10 | versions.push_back(v); 11 | } 12 | 13 | const CallableVersion* Callable::resolve(SemanticAnalyzer* analyzer, std::vector arguments) const { 14 | return nullptr; 15 | } 16 | 17 | bool Callable::is_compatible(int argument_count) { 18 | for (const auto& version : versions) { 19 | if (version.type->arguments().size() == (size_t) argument_count) return true; 20 | } 21 | return false; 22 | } 23 | 24 | } 25 | 26 | namespace std { 27 | std::ostream& operator << (std::ostream& os, const ls::Callable* callable) { 28 | os << "[" << std::endl; 29 | for (const auto& v : callable->versions) { 30 | os << " " << v << std::endl; 31 | } 32 | os << "]"; 33 | return os; 34 | } 35 | } -------------------------------------------------------------------------------- /src/analyzer/value/Object.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OBJECT_HPP 2 | #define OBJECT_HPP 3 | 4 | #include 5 | #include "Expression.hpp" 6 | #include "../lexical/Ident.hpp" 7 | 8 | namespace ls { 9 | 10 | class Object : public Value { 11 | public: 12 | 13 | std::vector keys; 14 | std::vector> values; 15 | Token* opening_brace = nullptr; 16 | Token* closing_brace = nullptr; 17 | 18 | Object(Environment& env); 19 | 20 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 21 | virtual Location location() const override; 22 | 23 | virtual void pre_analyze(SemanticAnalyzer*) override; 24 | virtual void analyze(SemanticAnalyzer*) override; 25 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 26 | 27 | #if COMPILER 28 | virtual Compiler::value compile(Compiler&) const override; 29 | #endif 30 | 31 | virtual std::unique_ptr clone(Block* parent) const override; 32 | }; 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/type/Interval_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef INTERVAL_TYPE_HPP 2 | #define INTERVAL_TYPE_HPP 3 | 4 | #include "Pointer_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Interval_type : public Pointer_type { 9 | public: 10 | Interval_type(Environment& env); 11 | virtual int id() const override { return 8; } 12 | virtual const std::string getName() const override { return "interval"; } 13 | virtual Json json() const override; 14 | virtual bool iterable() const override { return true; } 15 | virtual const Type* iterator() const override; 16 | virtual const Type* key() const override; 17 | virtual const Type* element() const override; 18 | virtual bool container() const override { return true; } 19 | virtual bool operator == (const Type*) const override; 20 | virtual int distance(const Type* type) const override; 21 | virtual std::string class_name() const override; 22 | virtual std::ostream& print(std::ostream& os) const override; 23 | virtual Type* clone() const override; 24 | }; 25 | 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /src/type/Meta_baseof_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef META_BASEOF_TYPE_HPP 2 | #define META_BASEOF_TYPE_HPP 3 | 4 | #include "Type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Meta_baseof_type : public Type { 9 | public: 10 | const Type* type; 11 | const Type* base; 12 | const Type* result = nullptr; 13 | Meta_baseof_type(const Type* type, const Type* base) : Type(type->env), type(type), base(base) {} 14 | virtual void reset() const override; 15 | virtual int id() const override { return 0; } 16 | virtual const std::string getName() const override { return "meta_baseof"; } 17 | virtual Json json() const override; 18 | virtual bool operator == (const Type*) const override; 19 | virtual int distance(const Type* type) const override; 20 | #if COMPILER 21 | virtual llvm::Type* llvm(Compiler& c) const override; 22 | #endif 23 | virtual std::string class_name() const override; 24 | virtual std::ostream& print(std::ostream& os) const override; 25 | virtual Type* clone() const override; 26 | }; 27 | 28 | } 29 | 30 | #endif -------------------------------------------------------------------------------- /src/vm/value/LSNull.cpp: -------------------------------------------------------------------------------- 1 | #include "LSNull.hpp" 2 | #include "LSClass.hpp" 3 | #include "LSNumber.hpp" 4 | #include "../VM.hpp" 5 | #include "../../environment/Environment.hpp" 6 | 7 | namespace ls { 8 | 9 | LSValue* LSNull::null_var; 10 | 11 | LSValue* LSNull::get() { 12 | return null_var; 13 | } 14 | 15 | LSNull::LSNull() : LSValue(LSValue::NULLL, 1, true) {} 16 | 17 | LSNull::~LSNull() {} 18 | 19 | bool LSNull::to_bool() const { 20 | return false; 21 | } 22 | 23 | bool LSNull::ls_not() const { 24 | return true; 25 | } 26 | 27 | bool LSNull::eq(const LSValue* v) const { 28 | return dynamic_cast(v); 29 | } 30 | 31 | bool LSNull::lt(const LSValue* v) const { 32 | if (dynamic_cast(v)) { 33 | return false; 34 | } 35 | return LSValue::lt(v); 36 | } 37 | 38 | std::ostream& LSNull::dump(std::ostream& os, int) const { 39 | os << "null"; 40 | return os; 41 | } 42 | 43 | LSValue* LSNull::getClass(VM* vm) const { 44 | return vm->env.null_class.get(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/analyzer/value/If.hpp: -------------------------------------------------------------------------------- 1 | #ifndef IF_HPP_ 2 | #define IF_HPP_ 3 | 4 | #include "Expression.hpp" 5 | #include "../value/Block.hpp" 6 | 7 | namespace ls { 8 | 9 | class Phi; 10 | 11 | class If : public Value { 12 | public: 13 | 14 | Token* token; 15 | std::unique_ptr condition; 16 | std::unique_ptr then; 17 | std::unique_ptr elze; 18 | bool ternary; 19 | std::vector phis; 20 | 21 | If(Environment& env, bool ternary = false); 22 | 23 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 24 | virtual Location location() const override; 25 | 26 | virtual void pre_analyze(SemanticAnalyzer*) override; 27 | virtual void analyze(SemanticAnalyzer*) override; 28 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 29 | 30 | #if COMPILER 31 | virtual Compiler::value compile(Compiler&) const override; 32 | #endif 33 | 34 | virtual std::unique_ptr clone(Block* parent) const override; 35 | }; 36 | 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/vm/value/LSClosure.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LSCLOSURE_HPP 2 | #define LSCLOSURE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../LSValue.hpp" 10 | #include "LSFunction.hpp" 11 | 12 | namespace ls { 13 | 14 | class LSClosure : public LSFunction { 15 | public: 16 | 17 | static LSClosure* constructor(VM* vm, void* f); 18 | 19 | std::vector captures; 20 | std::vector captures_native; // TODO check if necessary 21 | 22 | LSClosure(void* function); 23 | virtual ~LSClosure(); 24 | virtual bool closure() const; 25 | 26 | static void add_capture(LSClosure* closure, LSValue* value); 27 | static LSValue* get_capture(LSClosure* closure, int index); 28 | static LSValue** get_capture_l(LSClosure* closure, int index); 29 | }; 30 | 31 | template R call(LSClosure* function, A... args) { 32 | auto fun = (R (*)(void*, A...)) function->function; 33 | return fun(function, args...); 34 | } 35 | 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/type/Array_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ARRAY_TYPE_HPP 2 | #define ARRAY_TYPE_HPP 3 | 4 | #include "Pointer_type.hpp" 5 | #include 6 | 7 | namespace ls { 8 | 9 | class Type; 10 | 11 | class Array_type : public Pointer_type { 12 | const Type* const _element; 13 | public: 14 | Array_type(const Type* element); 15 | virtual int id() const override { return 5; } 16 | virtual const std::string getName() const override; 17 | virtual Json json() const override; 18 | virtual bool iterable() const override { return true; } 19 | virtual bool container() const override { return true; } 20 | virtual const Type* key() const override; 21 | virtual const Type* element() const override; 22 | virtual bool operator == (const Type*) const override; 23 | virtual int distance(const Type* type) const override; 24 | virtual const Type* iterator() const override; 25 | virtual std::string class_name() const override; 26 | virtual std::ostream& print(std::ostream&) const override; 27 | virtual Type* clone() const override; 28 | }; 29 | 30 | } 31 | 32 | #endif -------------------------------------------------------------------------------- /src/analyzer/value/PrefixExpression.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PREFIXEXPRESSION_HPP 2 | #define PREFIXEXPRESSION_HPP 3 | 4 | #include "Expression.hpp" 5 | #include "Value.hpp" 6 | #include "../lexical/Operator.hpp" 7 | 8 | namespace ls { 9 | 10 | class PrefixExpression : public Value { 11 | public: 12 | 13 | std::shared_ptr operatorr; 14 | std::unique_ptr expression; 15 | 16 | PrefixExpression(Environment& env, std::shared_ptr op, std::unique_ptr expression); 17 | 18 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 19 | virtual Location location() const override; 20 | 21 | virtual void pre_analyze(SemanticAnalyzer*) override; 22 | virtual void analyze(SemanticAnalyzer*) override; 23 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 24 | 25 | #if COMPILER 26 | virtual Compiler::value compile(Compiler&) const override; 27 | #endif 28 | 29 | virtual std::unique_ptr clone(Block* parent) const override; 30 | }; 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/type/Placeholder_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Placeholder_type.hpp" 2 | #include "../colors.h" 3 | #include "Type.hpp" 4 | #include "Any_type.hpp" 5 | #include "Meta_element_type.hpp" 6 | 7 | namespace ls { 8 | 9 | void Placeholder_type::implement(const Type* implementation) const { 10 | ((Placeholder_type*) this)->_implementation = implementation; 11 | } 12 | const Type* Placeholder_type::element() const { 13 | if (_element) return _element; 14 | ((Placeholder_type*) this)->_element = Type::meta_element(this); 15 | return _element; 16 | } 17 | bool Placeholder_type::operator == (const Type* type) const { 18 | return this == type; 19 | } 20 | int Placeholder_type::distance(const Type* type) const { 21 | return 0; 22 | } 23 | std::ostream& Placeholder_type::print(std::ostream& os) const { 24 | os << BLUE_BOLD << _name; 25 | if (_implementation != nullptr) { 26 | os << "." << _implementation; 27 | } 28 | os << END_COLOR; 29 | return os; 30 | } 31 | Type* Placeholder_type::clone() const { 32 | return new Placeholder_type { env, _name }; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/type/Map_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAP_TYPE_HPP 2 | #define MAP_TYPE_HPP 3 | 4 | #include "Pointer_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Type; 9 | 10 | class Map_type : public Pointer_type { 11 | const Type* const _key; 12 | const Type* const _element; 13 | public: 14 | Map_type(const Type* key, const Type* element); 15 | virtual int id() const override { return 6; } 16 | virtual const std::string getName() const override; 17 | virtual Json json() const override; 18 | virtual bool iterable() const override { return true; } 19 | virtual const Type* iterator() const override; 20 | virtual bool container() const override { return true; } 21 | virtual const Type* element() const override; 22 | virtual const Type* key() const override; 23 | virtual bool operator == (const Type*) const override; 24 | virtual int distance(const Type*) const override; 25 | virtual std::string class_name() const override; 26 | virtual std::ostream& print(std::ostream& os) const override; 27 | virtual Type* clone() const override; 28 | }; 29 | 30 | } 31 | 32 | #endif -------------------------------------------------------------------------------- /src/analyzer/instruction/ClassDeclaration.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLASSDECLARATION_HPP 2 | #define CLASSDECLARATION_HPP 3 | 4 | #include 5 | #include "Instruction.hpp" 6 | #include "VariableDeclaration.hpp" 7 | #include "../lexical/Ident.hpp" 8 | 9 | namespace ls { 10 | 11 | class LSClass; 12 | 13 | class ClassDeclaration : public Instruction { 14 | public: 15 | 16 | Token* token; 17 | std::string name; 18 | std::vector> fields; 19 | Variable* var; 20 | 21 | ClassDeclaration(Environment& env, Token* token); 22 | 23 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 24 | virtual Location location() const override; 25 | 26 | virtual void pre_analyze(SemanticAnalyzer* analyzer) override; 27 | virtual void analyze(SemanticAnalyzer*, const Type* req_type) override; 28 | 29 | #if COMPILER 30 | virtual Compiler::value compile(Compiler&) const override; 31 | #endif 32 | 33 | virtual std::unique_ptr clone(Block* parent) const override; 34 | }; 35 | 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/type/Any_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Any_type.hpp" 2 | #include "Type.hpp" 3 | #include "../colors.h" 4 | #include "Struct_type.hpp" 5 | #include "../environment/Environment.hpp" 6 | 7 | namespace ls { 8 | 9 | Any_type::Any_type(Environment& env, bool native) : Pointer_type(Type::structure("any", { 10 | env.integer, // ? 11 | env.integer, // ? 12 | env.integer, // ? 13 | env.integer, // refs 14 | env.boolean // native 15 | }), native) {} 16 | 17 | bool Any_type::operator == (const Type* type) const { 18 | return dynamic_cast(type); 19 | } 20 | int Any_type::distance(const Type* type) const { 21 | if (not temporary and type->temporary) return -1; 22 | if (dynamic_cast(type->folded)) { return 0; } 23 | return 100000 + type->distance(this); 24 | } 25 | std::string Any_type::class_name() const { 26 | return "Value"; 27 | } 28 | std::ostream& Any_type::print(std::ostream& os) const { 29 | os << BLUE_BOLD << "any" << END_COLOR; 30 | return os; 31 | } 32 | Type* Any_type::clone() const { 33 | return new Any_type { env }; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /test/code/euler/pe024.leek: -------------------------------------------------------------------------------- 1 | var p = 1 2 | 3 | for (var a = 0; a <= 9; ++a) 4 | for (var b = 0; b <= 9; ++b) 5 | if (b != a) 6 | for (var c = 0; c <= 9; ++c) 7 | if (c != b && c != a) 8 | for (var d = 0; d <= 9; ++d) 9 | if (d != c && d != b && d != a) 10 | for (var e = 0; e <= 9; ++e) 11 | if (e != d && e != c && e != b && e != a) 12 | for (var f = 0; f <= 9; ++f) 13 | if (f != e && f != d && f != c && f != b && f != a) 14 | for (var g = 0; g <= 9; ++g) 15 | if (g != f && g != e && g != d && g != c && g != b && g != a) 16 | for (var h = 0; h <= 9; ++h) 17 | if (h != g && h != f && h != e && h != d && h != c && h != b && h != a) 18 | for (var i = 0; i <= 9; ++i) 19 | if (i != h && i != g && i != f && i != e && i != d && i != c && i != b && i != a) 20 | for (var j = 0; j <= 9; ++j) 21 | if (j != i && j != h && j != g && j != f && j != e && j != d && j != c && j != b && j != a) { 22 | 23 | var n = a*1000000000L + b*100000000L + c*10000000L + d*1000000 + e*100000 + f*10000 + g*1000 + h*100 + i * 10 + j 24 | 25 | if (p++ == 1000000) { 26 | return n 27 | } 28 | } -------------------------------------------------------------------------------- /src/standard/class/BooleanSTD.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOLEAN_STD_HPP 2 | #define BOOLEAN_STD_HPP 3 | 4 | #include "../Module.hpp" 5 | 6 | namespace ls { 7 | 8 | class BooleanSTD : public Module { 9 | public: 10 | BooleanSTD(Environment& env); 11 | 12 | #if COMPILER 13 | 14 | static Compiler::value new_(Compiler& c, std::vector, int); 15 | 16 | static LSString* add(int boolean, LSString* string); 17 | static LSString* add_tmp(int boolean, LSString* string); 18 | static Compiler::value add_bool(Compiler& c, std::vector args, int); 19 | 20 | static Compiler::value sub_bool(Compiler& c, std::vector args, int); 21 | 22 | static Compiler::value mul_bool(Compiler& c, std::vector args, int); 23 | 24 | static int compare_ptr_ptr(LSBoolean* a, LSBoolean* b); 25 | static LSValue* compare_ptr_ptr_ptr(LSBoolean* a, LSBoolean* b); 26 | static Compiler::value compare_val_val(Compiler&, std::vector, int); 27 | 28 | static LSValue* to_string(bool b); 29 | 30 | #endif 31 | }; 32 | 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/vm/value/LSClass.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LSCLASS_HPP_ 2 | #define LSCLASS_HPP_ 3 | 4 | #include 5 | #include 6 | #include "../LSValue.hpp" 7 | #include "../../compiler/Compiler.hpp" 8 | #include "../../standard/TypeMutator.hpp" 9 | #include "../../analyzer/semantic/Callable.hpp" 10 | 11 | namespace ls { 12 | 13 | class Method; 14 | class ModuleStaticField; 15 | class Type; 16 | class Class; 17 | 18 | class LSClass : public LSValue { 19 | public: 20 | static LSClass* constructor(VM* vm, char* name); 21 | 22 | Class* clazz; 23 | 24 | LSClass(std::string); 25 | LSClass(Class* clazz); 26 | 27 | virtual ~LSClass(); 28 | 29 | bool to_bool() const override; 30 | virtual bool ls_not() const override; 31 | 32 | bool eq(const LSValue*) const override; 33 | bool lt(const LSValue*) const override; 34 | 35 | LSValue* attr(VM* vm, const std::string& key) const override; 36 | 37 | std::ostream& dump(std::ostream& os, int level) const override; 38 | std::string json() const override; 39 | 40 | LSValue* getClass(VM* vm) const override; 41 | }; 42 | 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /test/code/euler/pe018.leek: -------------------------------------------------------------------------------- 1 | 2 | 3 | var tryRoute = (level, x, sum, maxi) => { 4 | 5 | let tri = [ 6 | [75], 7 | [95, 64], 8 | [17, 47, 82], 9 | [18, 35, 87, 10], 10 | [20, 4, 82, 47, 65], 11 | [19, 1, 23, 75, 3, 34], 12 | [88, 2, 77, 73, 7, 63, 67], 13 | [99, 65, 4, 28, 6, 16, 70, 92], 14 | [41, 41, 26, 56, 83, 40, 80, 70, 33], 15 | [41, 48, 72, 33, 47, 32, 37, 16, 94, 29], 16 | [53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14], 17 | [70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57], 18 | [91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48], 19 | [63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31], 20 | [ 4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23] 21 | ] 22 | sum += tri[level][x] 23 | 24 | if (level == 14) { 25 | if (sum > maxi) maxi = sum 26 | return maxi 27 | } else { 28 | maxi = tryRoute(level + 1, x, sum, maxi) 29 | return tryRoute(level + 1, x + 1, sum, maxi) 30 | } 31 | } 32 | 33 | tryRoute(0, 0, 0, 0) 34 | 35 | -------------------------------------------------------------------------------- /src/analyzer/instruction/While.hpp: -------------------------------------------------------------------------------- 1 | #ifndef WHILE_HPP 2 | #define WHILE_HPP 3 | 4 | #include 5 | #include "../value/Value.hpp" 6 | #include "../value/Block.hpp" 7 | #include "../semantic/Mutation.hpp" 8 | 9 | namespace ls { 10 | 11 | class Variable; 12 | 13 | class While : public Instruction { 14 | public: 15 | 16 | Token* token; 17 | std::unique_ptr condition; 18 | std::unique_ptr body; 19 | std::vector mutations; 20 | 21 | While(Environment& env); 22 | 23 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 24 | virtual Location location() const override; 25 | 26 | virtual void pre_analyze(SemanticAnalyzer* analyzer) override; 27 | virtual void analyze(SemanticAnalyzer*, const Type* req_type) override; 28 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 29 | 30 | #if COMPILER 31 | virtual Compiler::value compile(Compiler&) const override; 32 | #endif 33 | 34 | virtual std::unique_ptr clone(Block* parent) const override; 35 | }; 36 | 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/type/Meta_baseof_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Meta_baseof_type.hpp" 2 | #include "../colors.h" 3 | #if COMPILER 4 | #include "../compiler/Compiler.hpp" 5 | #endif 6 | 7 | namespace ls { 8 | 9 | void Meta_baseof_type::reset() const { 10 | ((Meta_baseof_type*) this)->result = nullptr; 11 | type->reset(); 12 | } 13 | bool Meta_baseof_type::operator == (const Type* type) const { 14 | return false; 15 | } 16 | int Meta_baseof_type::distance(const Type* type) const { 17 | return -1; 18 | } 19 | #if COMPILER 20 | llvm::Type* Meta_baseof_type::llvm(Compiler& c) const { 21 | return llvm::Type::getVoidTy(c.getContext()); 22 | } 23 | #endif 24 | std::string Meta_baseof_type::class_name() const { 25 | return ""; 26 | } 27 | Json Meta_baseof_type::json() const { 28 | return { 29 | { "name", "baseof" }, 30 | { "element", type->json() } 31 | }; 32 | } 33 | std::ostream& Meta_baseof_type::print(std::ostream& os) const { 34 | os << C_GREY << type << " : " << base << END_COLOR; 35 | return os; 36 | } 37 | Type* Meta_baseof_type::clone() const { 38 | return new Meta_baseof_type(type, base); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /src/analyzer/resolver/File.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FILE_HPP 2 | #define FILE_HPP 3 | 4 | #include "FileContext.hpp" 5 | #include "../error/Error.hpp" 6 | #include 7 | #include 8 | #include "../lexical/Todo.hpp" 9 | 10 | namespace ls { 11 | 12 | class Program; 13 | 14 | class File { 15 | public: 16 | std::string path; 17 | std::string code; 18 | FileContext context; 19 | std::vector errors; 20 | std::vector tokens; 21 | Token finished_token; 22 | std::vector included_files; 23 | std::unordered_map includers_files; 24 | Program* program; 25 | bool entrypoint = false; 26 | File* waiting = nullptr; 27 | bool tokens_read = false; 28 | std::vector waiters; 29 | std::vector todos; 30 | std::unordered_set entrypoints; 31 | 32 | File(std::string path, std::string code, FileContext context, Program* program) : finished_token({ TokenType::FINISHED, this, 0, 0, 0, "" }) { 33 | this->path = path; 34 | this->code = code; 35 | this->context = context; 36 | this->program = program; 37 | } 38 | }; 39 | 40 | } 41 | 42 | #endif -------------------------------------------------------------------------------- /src/type/Struct_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef STRUCT_TYPE_HPP 2 | #define STRUCT_TYPE_HPP 3 | 4 | #include "Type.hpp" 5 | #if COMPILER 6 | #include "llvm/IR/DerivedTypes.h" 7 | #endif 8 | 9 | namespace ls { 10 | 11 | class Struct_type : public Type { 12 | std::string _name; 13 | std::vector _types; 14 | #if COMPILER 15 | llvm::StructType* _llvm_type = nullptr; 16 | #endif 17 | public: 18 | Struct_type(const std::string name, std::initializer_list types); 19 | Struct_type(const std::string name, std::vector types); 20 | virtual const std::string getName() const override { return "struct"; } 21 | virtual Json json() const override; 22 | virtual const Type* member(int) const override; 23 | virtual bool operator == (const Type*) const override; 24 | virtual int distance(const Type* type) const override; 25 | #if COMPILER 26 | virtual llvm::Type* llvm(Compiler& c) const override; 27 | #endif 28 | virtual std::string class_name() const override; 29 | virtual std::ostream& print(std::ostream& os) const override; 30 | virtual Type* clone() const override; 31 | }; 32 | 33 | } 34 | 35 | #endif -------------------------------------------------------------------------------- /src/doc/Array_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "average": { 3 | "desc": "Calcule la moyenne du tableau", 4 | "args": {}, 5 | "return": "La moyenne du tableau : la somme de toutes les valeurs divisé par la taille du tableau", 6 | "examples": [ 7 | "[1, 2, 3, 4, 5].average() // 3", 8 | "let grades = [12, 15.5, 16, 11.5, 19]\ngrades.average() // 14.8" 9 | ] 10 | }, 11 | "clear": { 12 | "desc": "Supprime tous les éléments du tableau", 13 | "args": {}, 14 | "return": "Le tableau lui-même" 15 | }, 16 | "contains": { 17 | "desc": "Vérifie si le tableau contient une valeur value", 18 | "args": { 19 | "value" : "La valeur à rechercher" 20 | }, 21 | "return": "true si le tableau contient la valeur value, false sinon" 22 | }, 23 | "fill": { 24 | "desc": "Redimensionne le tableau array à la taille size et remplit toutes ses cases avec value.", 25 | "args": { 26 | "value": " La valeur pour chaque case du tableau", 27 | "size": "Le nombre de cases" 28 | }, 29 | "return": "Le tableau lui-même", 30 | "examples": [ 31 | "var a = [4, 5, 6] a.fill(12) // [12, 12, 12]", 32 | "[].fill(1, 7) // [1, 1, 1, 1, 1, 1, 1]" 33 | ] 34 | } 35 | } -------------------------------------------------------------------------------- /src/type/Set_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SET_TYPE_HPP 2 | #define SET_TYPE_HPP 3 | 4 | #include 5 | #include "Pointer_type.hpp" 6 | 7 | namespace ls { 8 | 9 | class Type; 10 | 11 | class Set_type : public Pointer_type { 12 | const Type* const _element; 13 | public: 14 | Set_type(const Type* element); 15 | virtual int id() const override { return 7; } 16 | virtual const std::string getName() const override; 17 | virtual Json json() const override; 18 | virtual bool iterable() const override { return true; } 19 | virtual const Type* iterator() const override; 20 | virtual bool container() const override { return true; } 21 | virtual const Type* key() const override; 22 | virtual const Type* element() const override; 23 | virtual bool operator == (const Type*) const override; 24 | virtual int distance(const Type* type) const override; 25 | virtual std::string class_name() const override; 26 | virtual std::ostream& print(std::ostream&) const override; 27 | virtual Type* clone() const override; 28 | 29 | static const Type* get_node_type(const Type* element); 30 | static const Type* get_iterator(const Type* element); 31 | }; 32 | 33 | } 34 | 35 | #endif -------------------------------------------------------------------------------- /test/code/ai.leek: -------------------------------------------------------------------------------- 1 | function isWeapon(w) { 2 | if (w == 12) return true 3 | return false 4 | } 5 | function isChip(w) { 6 | if (w != 12) return true 7 | return false 8 | } 9 | function getChipCooldown(x) { 10 | return 0 11 | } 12 | function count(array) { 13 | return Array.size(array) 14 | } 15 | function inArray(array, element) { 16 | return Array.contains(array, element) 17 | } 18 | 19 | function _partition(n, si, items, added) { 20 | 21 | var combos = []; 22 | for (var i = si; i < count(items); i++) { 23 | 24 | var item = items[i]; 25 | var cost = item[1]; 26 | 27 | if (isWeapon(item[0]) && inArray(added, item)) cost--; 28 | 29 | if (cost > n) continue; 30 | 31 | if (isChip(item[0]) && getChipCooldown(item[0]) > 0 && inArray(added, item)) continue; 32 | 33 | added += item; 34 | 35 | var subs = _partition(n - cost, i, items, added); 36 | if (count(subs) > 0) { 37 | for (var sub in subs) { Array.push(combos, [ 38 | [item[0], cost] 39 | ] + sub); } 40 | } else { 41 | Array.push(combos, [ 42 | [item[0], cost] 43 | ]); 44 | } 45 | } 46 | combos; 47 | } 48 | 49 | var items = [12, 5, 18] 50 | 51 | _partition(10, 0, items, []) 52 | -------------------------------------------------------------------------------- /src/analyzer/instruction/ExpressionInstruction.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EXPRESSIONINSTRUCTION_HPP 2 | #define EXPRESSIONINSTRUCTION_HPP 3 | 4 | #include "Instruction.hpp" 5 | 6 | namespace ls { 7 | 8 | class ExpressionInstruction : public Instruction { 9 | public: 10 | 11 | std::unique_ptr value; 12 | 13 | ExpressionInstruction(Environment& env, std::unique_ptr expression); 14 | 15 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 16 | virtual Location location() const override; 17 | 18 | virtual void set_end_section(Section*) override; 19 | 20 | virtual void pre_analyze(SemanticAnalyzer* analyzer) override; 21 | 22 | virtual void analyze(SemanticAnalyzer*, const Type* type) override; 23 | virtual Completion autocomplete(SemanticAnalyzer& analyzer, size_t position) const override; 24 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 25 | 26 | #if COMPILER 27 | virtual Compiler::value compile(Compiler&) const override; 28 | virtual void compile_end(Compiler&) const override; 29 | #endif 30 | 31 | virtual std::unique_ptr clone(Block* parent) const override; 32 | }; 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/analyzer/instruction/For.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FOR_HPP 2 | #define FOR_HPP 3 | 4 | #include 5 | #include "../value/Value.hpp" 6 | #include "../value/Block.hpp" 7 | #include "Instruction.hpp" 8 | #include "../semantic/Mutation.hpp" 9 | 10 | namespace ls { 11 | 12 | class Block; 13 | class Variable; 14 | 15 | class For : public Instruction { 16 | public: 17 | 18 | Token* token; 19 | std::unique_ptr init; 20 | std::unique_ptr condition; 21 | std::unique_ptr increment; 22 | std::unique_ptr body; 23 | std::vector mutations; 24 | 25 | For(Environment& env); 26 | 27 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 28 | virtual Location location() const override; 29 | 30 | virtual void pre_analyze(SemanticAnalyzer* analyzer) override; 31 | virtual void analyze(SemanticAnalyzer*, const Type* req_type) override; 32 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 33 | 34 | #if COMPILER 35 | virtual Compiler::value compile(Compiler&) const override; 36 | #endif 37 | 38 | virtual std::unique_ptr clone(Block* parent) const override; 39 | }; 40 | 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/type/Void_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Void_type.hpp" 2 | #include "../colors.h" 3 | #include "../environment/Environment.hpp" 4 | #if COMPILER 5 | #include "../compiler/Compiler.hpp" 6 | #endif 7 | 8 | namespace ls { 9 | 10 | const Type* Void_type::element() const { 11 | return env.void_; 12 | } 13 | const Type* Void_type::key() const { 14 | return env.void_; 15 | } 16 | const Type* Void_type::return_type() const { 17 | return env.void_; 18 | } 19 | 20 | bool Void_type::operator == (const Type* type) const { 21 | return type == env.void_; 22 | } 23 | int Void_type::distance(const Type* type) const { 24 | if (dynamic_cast(type->folded)) { return 1; } 25 | return -1; 26 | } 27 | #if COMPILER 28 | llvm::Type* Void_type::llvm(Compiler& c) const { 29 | return llvm::Type::getVoidTy(c.getContext()); 30 | } 31 | #endif 32 | std::string Void_type::class_name() const { 33 | return ""; 34 | } 35 | Json Void_type::json() const { 36 | return { 37 | { "name", "void" } 38 | }; 39 | } 40 | std::ostream& Void_type::print(std::ostream& os) const { 41 | os << C_GREY << "void" << END_COLOR; 42 | return os; 43 | } 44 | Type* Void_type::clone() const { 45 | return new Void_type { env }; 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/doc/Number_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "static/pi": { 3 | "desc": "Le nombre pi. Peut s'écrire 'π' au lieu de Number.pi" 4 | }, 5 | "abs": { 6 | "desc": "Renvoie la valeur absolue du nombre number.", 7 | "args": { 8 | "x": "Le nombre dont la valeur absolue sera calculée." 9 | }, 10 | "return": "La valeur absolue du nombre " 11 | }, 12 | "acos": { 13 | "desc": "Calcule l'arc cosinus du nombre, dans l'intervalle [0, #Number.pi].", 14 | "args": {}, 15 | "return": "L'arc cosinus du nombre." 16 | }, 17 | "acos": { 18 | "desc": "Calcule l'arc sinus d'argument, dans l'intervalle [0, PI].", 19 | "args": {}, 20 | "return": "L'arc sinus du nombre." 21 | }, 22 | "atan": { 23 | "desc": "Calcule l'arc tangente d'argument, dans l'intervalle [0, PI].", 24 | "args": {}, 25 | "return": "L'arc tangente d'argument." 26 | }, 27 | "atan2": { 28 | "desc": "Convertit les coordonnées cartésiennes (x, y) en coordonnées polaires (r, theta). Cette fonction retourne l'angle theta entre -PI et PI en utilisant les signes des arguments.", 29 | "args": { 30 | "y": "Coordonnée en y.", 31 | "x": "Coordonnée en x." 32 | }, 33 | "return": "L'angle theta en coordonnées polaires du point (x, y)." 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/code/reachable_cells.leek: -------------------------------------------------------------------------------- 1 | var obstacles = [100 118 136 151 153 154 169 170 172 185 187 202 205 219 223 236 237 253 255 273 291 321 322 339 340 341 356 358 359 374 375 389 392 406 407 409 423 425 427 441 442 459 477 495] 2 | var leeks = [168 309 327] 3 | 4 | function reachable_cells(start, mp, obstacles, leeks) { 5 | 6 | var neighbours = function(c, obstacles, leeks) { 7 | 8 | var n = [] 9 | var n1 = c + 17 10 | if !obstacles.contains(n1) and !leeks.contains(n1) { n += n1 } 11 | var n2 = c + 18 12 | if !obstacles.contains(n2) and !leeks.contains(n2) { n += n2 } 13 | var n3 = c - 17 14 | if !obstacles.contains(n3) and !leeks.contains(n3) { n += n3 } 15 | var n4 = c - 18 16 | if !obstacles.contains(n4) and !leeks.contains(n4) { n += n4 } 17 | return n 18 | } 19 | 20 | var cells = [start] 21 | var grow = [start] 22 | 23 | while mp-- { 24 | var res = [] 25 | for var cell in grow { 26 | var n = neighbours(cell, obstacles, leeks) 27 | for c in n { 28 | if !cells.contains(c) and !res.contains(c) { 29 | res += c 30 | } 31 | } 32 | } 33 | grow = res 34 | cells += res 35 | } 36 | return cells 37 | } 38 | 39 | reachable_cells(306, 15, obstacles, leeks).size() 40 | -------------------------------------------------------------------------------- /src/analyzer/value/String.cpp: -------------------------------------------------------------------------------- 1 | #include "String.hpp" 2 | #include "../semantic/SemanticAnalyzer.hpp" 3 | #include "../../type/Type.hpp" 4 | 5 | namespace ls { 6 | 7 | String::String(Environment& env, Token* token) : Value(env), token(token) { 8 | type = env.tmp_string; 9 | constant = true; 10 | } 11 | 12 | void String::print(std::ostream& os, int, PrintOptions options) const { 13 | os << "'" << token->content << "'"; 14 | if (options.debug) { 15 | os << " " << type; 16 | } 17 | } 18 | 19 | Location String::location() const { 20 | return token->location; 21 | } 22 | 23 | bool String::will_store(SemanticAnalyzer* analyzer, const Type* type) { 24 | if (!type->is_string()) { 25 | analyzer->add_error({Error::Type::NO_SUCH_OPERATOR, ErrorLevel::ERROR, location(), location(), {this->type->to_string(), "=", type->to_string()}}); 26 | } 27 | return false; 28 | } 29 | 30 | #if COMPILER 31 | Compiler::value String::compile(Compiler& c) const { 32 | auto s = c.new_const_string(token->content); 33 | return c.insn_call(c.env.tmp_string, {s}, "String.new.1"); 34 | } 35 | #endif 36 | 37 | std::unique_ptr String::clone(Block* parent) const { 38 | return std::make_unique(type->env, token); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/analyzer/value/Expression.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EXPRESSION_HPP 2 | #define EXPRESSION_HPP 3 | 4 | #include 5 | #include "../../analyzer/lexical/Operator.hpp" 6 | #include "../../analyzer/value/Value.hpp" 7 | #include "../semantic/CallableVersion.hpp" 8 | 9 | namespace ls { 10 | 11 | class Callable; 12 | class CallableVersion; 13 | 14 | class Expression : public Value { 15 | public: 16 | 17 | std::unique_ptr v1; 18 | std::unique_ptr v2; 19 | std::shared_ptr op; 20 | int operations; 21 | CallableVersion callable_version; 22 | 23 | Expression(Environment& env, Value* = nullptr); 24 | 25 | void append(std::shared_ptr, Value*); 26 | 27 | void print(std::ostream&, int indent, PrintOptions options) const override; 28 | virtual Location location() const override; 29 | 30 | virtual void pre_analyze(SemanticAnalyzer*) override; 31 | virtual void analyze(SemanticAnalyzer*) override; 32 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 33 | 34 | #if COMPILER 35 | virtual Compiler::value compile(Compiler&) const override; 36 | #endif 37 | 38 | virtual std::unique_ptr clone(Block* parent) const override; 39 | }; 40 | 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/analyzer/Context.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONTEXT_HPP 2 | #define CONTEXT_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include "../analyzer/semantic/Variable.hpp" 8 | #include "../environment/Environment.hpp" 9 | 10 | namespace ls { 11 | 12 | union ContextVarValue { 13 | LSValue* ls_value; 14 | int int_value; 15 | double real_value; 16 | long long_value; 17 | ContextVarValue() : int_value(0) {} 18 | ContextVarValue(int v) : int_value(v) {} 19 | ContextVarValue(LSValue* v) : ls_value(v) {} 20 | ContextVarValue(double v) : real_value(v) {} 21 | ContextVarValue(long v) : long_value(v) {} 22 | }; 23 | 24 | class ContextVar { 25 | public: 26 | ContextVarValue value; 27 | const Type* type; 28 | Variable* variable; 29 | std::unique_ptr token; 30 | }; 31 | 32 | class Context { 33 | public: 34 | 35 | Environment& env; 36 | std::unordered_map vars; 37 | 38 | Context(Environment& env); 39 | Context(Environment& env, std::string ctx); 40 | virtual ~Context(); 41 | 42 | void add_variable(char* name, ContextVarValue v, const Type* type); 43 | }; 44 | 45 | } 46 | 47 | namespace std { 48 | std::ostream& operator << (std::ostream&, const ls::Context*); 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/type/Pointer_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef POINTER_TYPE_HPP 2 | #define POINTER_TYPE_HPP 3 | 4 | #include "Type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Pointer_type : public Type { 9 | const Type* const _type; 10 | #if COMPILER 11 | llvm::Type* _llvm_type = nullptr; 12 | #endif 13 | public: 14 | Pointer_type(const Type* type, bool native = false); 15 | virtual ~Pointer_type() {} 16 | virtual const Type* pointed() const override; 17 | virtual const Value* function() const override; 18 | virtual const Type* return_type() const override; 19 | virtual const Type* argument(size_t) const override; 20 | virtual const std::vector& arguments() const override; 21 | virtual const std::string getName() const override { return _type->getName() + "*"; } 22 | virtual Json json() const override; 23 | virtual bool callable() const override; 24 | virtual bool operator == (const Type*) const override; 25 | virtual int distance(const Type* type) const override; 26 | #if COMPILER 27 | virtual llvm::Type* llvm(Compiler& c) const override; 28 | #endif 29 | virtual std::string class_name() const override; 30 | virtual std::ostream& print(std::ostream& os) const override; 31 | virtual Type* clone() const override; 32 | }; 33 | 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /src/analyzer/value/Array.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ARRAY_HPP 2 | #define ARRAY_HPP 3 | 4 | #include 5 | #include 6 | #include "Value.hpp" 7 | #include "../lexical/Token.hpp" 8 | 9 | namespace ls { 10 | 11 | class Array : public Value { 12 | public: 13 | 14 | Token* opening_bracket; 15 | Token* closing_bracket; 16 | std::vector> expressions; 17 | 18 | Array(Environment& env); 19 | 20 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 21 | virtual Location location() const override; 22 | 23 | virtual void pre_analyze(SemanticAnalyzer*) override; 24 | virtual void analyze(SemanticAnalyzer*) override; 25 | void elements_will_take(SemanticAnalyzer*, const std::vector&, int level); 26 | virtual bool will_store(SemanticAnalyzer* analyzer, const Type* type) override; 27 | virtual bool elements_will_store(SemanticAnalyzer* analyzer, const Type* type, int level) override; 28 | 29 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 30 | 31 | #if COMPILER 32 | virtual Compiler::value compile(Compiler&) const override; 33 | #endif 34 | 35 | virtual std::unique_ptr clone(Block* parent) const override; 36 | }; 37 | 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/analyzer/value/Number.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NUMBER_HPP 2 | #define NUMBER_HPP 3 | 4 | #include 5 | #include "Value.hpp" 6 | #include "../lexical/Token.hpp" 7 | #if COMPILER 8 | #include 9 | #endif 10 | 11 | namespace ls { 12 | 13 | class Number : public Value { 14 | public: 15 | 16 | Token* token; 17 | std::string value; 18 | std::string clean_value; 19 | int base = 10; 20 | int int_value = 0; 21 | long long_value = 0; 22 | double double_value = 0; 23 | #if COMPILER 24 | mpz_t mpz_value; 25 | mpf_t mpf_value; 26 | bool mpz_value_initialized = false; 27 | #endif 28 | bool pointer = false; 29 | 30 | Number(Environment& env, std::string value, Token* token); 31 | virtual ~Number(); 32 | 33 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 34 | virtual Location location() const override; 35 | 36 | virtual void analyze(SemanticAnalyzer*) override; 37 | virtual bool is_zero() const override; 38 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 39 | 40 | #if COMPILER 41 | virtual Compiler::value compile(Compiler&) const override; 42 | #endif 43 | 44 | virtual std::unique_ptr clone(Block* parent) const override; 45 | }; 46 | 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/type/Null_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Null_type.hpp" 2 | #include "Type.hpp" 3 | #include "../colors.h" 4 | #include "Pointer_type.hpp" 5 | #include "Struct_type.hpp" 6 | #include "Any_type.hpp" 7 | #include "../environment/Environment.hpp" 8 | 9 | namespace ls { 10 | 11 | Null_type::Null_type(Environment& env) : Pointer_type(Type::structure("null", { 12 | env.integer, // ? 13 | env.integer, // ? 14 | env.integer, // ? 15 | env.integer, // refs 16 | env.boolean // native 17 | }), true) {} 18 | 19 | bool Null_type::operator == (const Type* type) const { 20 | return dynamic_cast(type); 21 | } 22 | int Null_type::distance(const Type* type) const { 23 | if (not temporary and type->temporary) return -1; 24 | if (dynamic_cast(type->folded)) { return 1; } 25 | if (dynamic_cast(type->folded)) { return 0; } 26 | return -1; 27 | } 28 | std::string Null_type::class_name() const { 29 | return "Null"; 30 | } 31 | Json Null_type::json() const { 32 | return { 33 | { "name", "null" } 34 | }; 35 | } 36 | std::ostream& Null_type::print(std::ostream& os) const { 37 | os << BLUE_BOLD << "null" << END_COLOR; 38 | return os; 39 | } 40 | Type* Null_type::clone() const { 41 | return new Null_type { env }; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /src/type/Object_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Object_type.hpp" 2 | #include "../colors.h" 3 | #include "Type.hpp" 4 | #include "Struct_type.hpp" 5 | #include "Any_type.hpp" 6 | #include "../environment/Environment.hpp" 7 | 8 | namespace ls { 9 | 10 | Object_type::Object_type(Environment& env, bool native) : Pointer_type(Type::structure("object", { 11 | env.integer, // ? 12 | env.integer, // ? 13 | env.integer, // ? 14 | env.integer, // refs 15 | env.boolean // native 16 | }), native) {} 17 | 18 | bool Object_type::operator == (const Type* type) const { 19 | return dynamic_cast(type); 20 | } 21 | int Object_type::distance(const Type* type) const { 22 | if (not temporary and type->temporary) return -1; 23 | if (dynamic_cast(type->folded)) { return 1; } 24 | if (dynamic_cast(type->folded)) { return 0; } 25 | return -1; 26 | } 27 | std::string Object_type::class_name() const { 28 | return "Object"; 29 | } 30 | Json Object_type::json() const { 31 | return { 32 | { "name", "object" } 33 | }; 34 | } 35 | std::ostream& Object_type::print(std::ostream& os) const { 36 | os << BLUE_BOLD << "object" << END_COLOR; 37 | return os; 38 | } 39 | Type* Object_type::clone() const { 40 | return new Object_type { env }; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /src/vm/value/LSClosure.cpp: -------------------------------------------------------------------------------- 1 | #include "LSClosure.hpp" 2 | #include "LSNull.hpp" 3 | #include "LSClass.hpp" 4 | #include "LSNumber.hpp" 5 | #include "LSArray.hpp" 6 | #include "../LSValue.hpp" 7 | #include "../../vm/VM.hpp" 8 | 9 | namespace ls { 10 | 11 | LSClosure* LSClosure::constructor(VM* vm, void* f) { 12 | auto c = new LSClosure(f); 13 | vm->function_created.push_back(c); 14 | return c; 15 | } 16 | 17 | LSClosure::LSClosure(void* function) : LSFunction(function) { 18 | type = CLOSURE; 19 | } 20 | 21 | LSClosure::~LSClosure() { 22 | for (size_t i = 0; i < captures.size(); ++i) { 23 | if (!captures_native[i] and captures[i] != this) { 24 | LSValue::delete_ref(captures[i]); 25 | } 26 | } 27 | } 28 | 29 | bool LSClosure::closure() const { 30 | return true; 31 | } 32 | 33 | void LSClosure::add_capture(LSClosure* closure, LSValue* value) { 34 | if (!value->native && value != closure) { 35 | value->refs++; 36 | } 37 | closure->captures.push_back(value); 38 | closure->captures_native.push_back(value->native); 39 | } 40 | 41 | LSValue* LSClosure::get_capture(LSClosure* closure, int index) { 42 | return closure->captures[index]; 43 | } 44 | LSValue** LSClosure::get_capture_l(LSClosure* closure, int index) { 45 | return &closure->captures[index]; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/standard/class/ClassSTD.cpp: -------------------------------------------------------------------------------- 1 | #include "ClassSTD.hpp" 2 | #include "../../type/Type.hpp" 3 | #include "../../environment/Environment.hpp" 4 | #if COMPILER 5 | #include "../../vm/value/LSClass.hpp" 6 | #endif 7 | 8 | namespace ls { 9 | 10 | ClassSTD::ClassSTD(Environment& env) : Module(env, "Class") { 11 | 12 | #if COMPILER 13 | env.class_class = std::make_unique(clazz.get()); 14 | lsclass = env.class_class.get(); 15 | #endif 16 | 17 | field("name", env.string); 18 | 19 | constructor_({ 20 | {env.clazz(), {env.i8_ptr, env.i8_ptr}, ADDR((void*) LSClass::constructor)}, 21 | }); 22 | 23 | method("construct", { 24 | {env.any, {env.clazz()}, ADDR(construct)} 25 | }); 26 | 27 | /** Internal **/ 28 | method("add_field", { 29 | {env.void_, {env.clazz(), env.i8_ptr, env.any}, ADDR((void*) add_field)} 30 | }, PRIVATE); 31 | } 32 | 33 | #if COMPILER 34 | 35 | Compiler::value ClassSTD::construct(Compiler& c, std::vector args, int) { 36 | return c.new_object_class(args[0]); 37 | } 38 | 39 | void ClassSTD::add_field(LSClass* clazz, char* field_name, LSValue* default_value) { 40 | clazz->clazz->addField(field_name, clazz->clazz->env.any, nullptr); 41 | clazz->clazz->fields.at(field_name).default_value = default_value; 42 | } 43 | 44 | #endif 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/type/Fixed_array_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FIXED_ARRAY_TYPE_HPP 2 | #define FIXED_ARRAY_TYPE_HPP 3 | 4 | #include "Array_type.hpp" 5 | #include 6 | 7 | namespace ls { 8 | 9 | class Type; 10 | 11 | class Fixed_array_type : public Array_type { 12 | std::vector _elements; 13 | const Type* _element; 14 | public: 15 | Fixed_array_type(const std::vector&); 16 | virtual int id() const override { return 5; } 17 | virtual const std::string getName() const override; 18 | virtual Json json() const override; 19 | virtual bool iterable() const override { return true; } 20 | virtual bool container() const override { return true; } 21 | virtual const Type* key() const override; 22 | virtual const Type* element() const override; 23 | virtual const Type* element(size_t index) const override; 24 | virtual const std::vector& elements() const override; 25 | virtual size_t size() const override; 26 | virtual bool operator == (const Type*) const override; 27 | virtual int distance(const Type* type) const override; 28 | virtual const Type* iterator() const override; 29 | virtual std::string class_name() const override; 30 | virtual std::ostream& print(std::ostream&) const override; 31 | virtual Type* clone() const override; 32 | }; 33 | 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /src/type/Compound_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMPOUND_TYPE_HPP 2 | #define COMPOUND_TYPE_HPP 3 | 4 | #include 5 | #include "Type.hpp" 6 | 7 | namespace ls { 8 | 9 | class Compound_type : public Type { 10 | public: 11 | std::vector types; 12 | Compound_type(std::set types, const Type* folded); 13 | virtual int id() const override { return 0; } 14 | virtual const Type* element() const override; 15 | virtual const Type* pointed() const override; 16 | virtual const std::string getName() const override; 17 | virtual Json json() const override; 18 | virtual bool operator == (const Type*) const override; 19 | virtual bool callable() const override; 20 | virtual bool container() const override; 21 | virtual bool iterable() const override; 22 | bool all(std::function fun) const; 23 | bool some(std::function fun) const; 24 | const Type* filter(std::function fun) const; 25 | virtual int distance(const Type* type) const override; 26 | virtual void implement(const Type* type) const override; 27 | #if COMPILER 28 | virtual llvm::Type* llvm(Compiler& c) const override; 29 | #endif 30 | virtual std::string class_name() const override; 31 | virtual std::ostream& print(std::ostream& os) const override; 32 | virtual Type* clone() const override; 33 | }; 34 | 35 | } 36 | 37 | #endif -------------------------------------------------------------------------------- /src/type/Function_object_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FUNCTION_OBJECT_TYPE_HPP 2 | #define FUNCTION_OBJECT_TYPE_HPP 3 | 4 | #include "Pointer_type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Type; 9 | class Value; 10 | 11 | class Function_object_type : public Pointer_type { 12 | const Type* const _return_type; 13 | std::vector _arguments; 14 | bool _closure; 15 | const Value* _function; 16 | public: 17 | Function_object_type(const Type*, const std::vector&, bool closure = false, const Value* function = nullptr); 18 | bool closure() const { return _closure; } 19 | const Value* function() const override { return _function; } 20 | virtual int id() const override { return 9; } 21 | virtual const std::string getName() const override { return "function"; }; 22 | virtual Json json() const override; 23 | virtual bool callable() const override { return true; } 24 | virtual bool operator == (const Type*) const override; 25 | virtual int distance(const Type* type) const override; 26 | virtual const Type* return_type() const override; 27 | virtual const std::vector& arguments() const override; 28 | virtual const Type* argument(size_t) const override; 29 | virtual std::string class_name() const override; 30 | virtual std::ostream& print(std::ostream& os) const override; 31 | virtual Type* clone() const override; 32 | }; 33 | 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /src/analyzer/instruction/Continue.cpp: -------------------------------------------------------------------------------- 1 | #include "Continue.hpp" 2 | #include "../semantic/SemanticAnalyzer.hpp" 3 | #include "../error/Error.hpp" 4 | 5 | namespace ls { 6 | 7 | Continue::Continue(Environment& env) : Instruction(env) { 8 | deepness = 1; 9 | jumping = true; 10 | jump_to_existing_section = true; 11 | breaking = true; 12 | } 13 | 14 | void Continue::print(std::ostream& os, int, PrintOptions) const { 15 | os << "continue"; 16 | if (deepness > 1) { 17 | os << " " << deepness; 18 | } 19 | } 20 | 21 | Location Continue::location() const { 22 | return token->location; 23 | } 24 | 25 | void Continue::analyze(SemanticAnalyzer* analyzer, const Type*) { 26 | 27 | // continue must be in a loop 28 | if (!analyzer->in_loop(deepness)) { 29 | analyzer->add_error({ Error::Type::CONTINUE_MUST_BE_IN_LOOP, ErrorLevel::ERROR, location(), location() }); 30 | } 31 | } 32 | 33 | #if COMPILER 34 | Compiler::value Continue::compile(Compiler& c) const { 35 | c.delete_variables_block(c.get_current_loop_blocks(deepness)); 36 | // c.insn_branch(c.get_current_loop_cond_section(deepness)); 37 | // c.insert_new_generation_block(); 38 | return { c.env }; 39 | } 40 | #endif 41 | 42 | std::unique_ptr Continue::clone(Block* parent) const { 43 | auto c = std::make_unique(type->env); 44 | c->deepness = deepness; 45 | c->token = token; 46 | return c; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/analyzer/semantic/CallableVersion.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CALLABLE_VERSION_HPP 2 | #define CALLABLE_VERSION_HPP 3 | 4 | #include 5 | #include 6 | #include "../../constants.h" 7 | #if COMPILER 8 | #include "../../compiler/Compiler.hpp" 9 | #endif 10 | 11 | namespace ls { 12 | 13 | class CallableVersionTemplate; 14 | class SemanticAnalyzer; 15 | class Type; 16 | class Value; 17 | class Callable; 18 | class Environment; 19 | 20 | class CallableVersion { 21 | const Callable* callable = nullptr; 22 | size_t index = 0; 23 | public: 24 | const Type* type = nullptr; 25 | #if COMPILER 26 | Compiler::value extra_arg; 27 | #endif 28 | 29 | CallableVersion(Environment&); 30 | CallableVersion(Environment&, const Callable*, size_t index, const Type*); 31 | 32 | const CallableVersionTemplate* template_() const; 33 | operator bool() const; 34 | 35 | void apply_mutators(SemanticAnalyzer* analyzer, std::vector arguments) const; 36 | 37 | #if COMPILER 38 | int compile_mutators(Compiler& c, std::vector arguments) const; 39 | Compiler::value compile_call(Compiler& c, std::vector args, const Value* value, int flags) const; 40 | #endif 41 | }; 42 | 43 | } 44 | 45 | namespace std { 46 | std::ostream& operator << (std::ostream&, const ls::CallableVersion&); 47 | std::ostream& operator << (std::ostream&, const ls::CallableVersion*); 48 | } 49 | 50 | #endif -------------------------------------------------------------------------------- /src/standard/class/MapSTD.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VM_STANDARD_MAPSTD_HPP_ 2 | #define VM_STANDARD_MAPSTD_HPP_ 3 | 4 | #include "../Module.hpp" 5 | 6 | namespace ls { 7 | 8 | class MapSTD : public Module { 9 | public: 10 | MapSTD(Environment& env); 11 | 12 | #if COMPILER 13 | 14 | static Compiler::value in(Compiler&, std::vector, int); 15 | 16 | static Compiler::value look(Compiler&, std::vector, int); 17 | static Compiler::value insert(Compiler& c, std::vector args, int); 18 | static Compiler::value clear(Compiler& c, std::vector args, int); 19 | static Compiler::value fold_left(Compiler&, std::vector, int); 20 | static Compiler::value fold_right(Compiler&, std::vector, int); 21 | static Compiler::value iter(Compiler& c, std::vector, int); 22 | static Compiler::value values(Compiler& c, std::vector, int); 23 | static Compiler::value min(Compiler& c, std::vector, int); 24 | static Compiler::value min_key(Compiler& c, std::vector, int); 25 | static Compiler::value max(Compiler& c, std::vector, int); 26 | static Compiler::value max_key(Compiler& c, std::vector, int); 27 | static Compiler::value erase(Compiler& c, std::vector, int); 28 | 29 | #endif 30 | }; 31 | 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/type/Class_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Class_type.hpp" 2 | #include "../colors.h" 3 | #include "Type.hpp" 4 | #include "Any_type.hpp" 5 | #include "Struct_type.hpp" 6 | #include "../environment/Environment.hpp" 7 | 8 | namespace ls { 9 | 10 | Class_type::Class_type(Environment& env, std::string name) : Pointer_type(Type::structure(name, { 11 | env.integer, // ? 12 | env.integer, // ? 13 | env.integer, // ? 14 | env.integer, // refs 15 | env.boolean // native 16 | }), true), name(name) {} 17 | 18 | bool Class_type::operator == (const Type* type) const { 19 | return dynamic_cast(type); 20 | } 21 | int Class_type::distance(const Type* type) const { 22 | if (not temporary and type->temporary) return -1; 23 | if (dynamic_cast(type->folded)) { return 1; } 24 | if (dynamic_cast(type->folded)) { return 0; } 25 | return -1; 26 | } 27 | std::string Class_type::class_name() const { 28 | return "Class"; 29 | } 30 | const std::string Class_type::getName() const { 31 | if (name == "?") { 32 | return "class"; 33 | } 34 | return "class " + name; 35 | } 36 | Json Class_type::json() const { 37 | return { 38 | { "name", "class" } 39 | }; 40 | } 41 | std::ostream& Class_type::print(std::ostream& os) const { 42 | os << BLUE_BOLD << "class" << END_COLOR; 43 | return os; 44 | } 45 | Type* Class_type::clone() const { 46 | return new Class_type { env, name }; 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/vm/Exception.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EXCEPTION_HPP 2 | #define EXCEPTION_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace ls { 10 | 11 | class VM; 12 | 13 | namespace vm { 14 | 15 | enum Exception { 16 | DIVISION_BY_ZERO = -2, 17 | NO_EXCEPTION = 0, 18 | EXCEPTION = 1, 19 | OPERATION_LIMIT_EXCEEDED = 2, 20 | NUMBER_OVERFLOW = 3, 21 | NO_SUCH_OPERATOR = 4, 22 | ARRAY_OUT_OF_BOUNDS = 5, 23 | ARRAY_KEY_IS_NOT_NUMBER = 6, 24 | CANT_MODIFY_READONLY_OBJECT = 7, 25 | NO_SUCH_ATTRIBUTE = 8, 26 | WRONG_ARGUMENT_TYPE = 9 27 | }; 28 | 29 | struct exception_frame { 30 | size_t line; 31 | std::string file; 32 | std::string function; 33 | void* frame; 34 | void* pc; 35 | exception_frame() {} 36 | exception_frame(std::string file, std::string function, size_t line) : line(line), file(file), function(function) {} 37 | bool operator == (const exception_frame& o) const { 38 | return file == o.file and line == o.line and function == o.function; 39 | } 40 | }; 41 | 42 | struct ExceptionObj : public std::exception { 43 | Exception type; 44 | std::vector frames; 45 | ExceptionObj() : ExceptionObj(NO_EXCEPTION) {} 46 | ExceptionObj(Exception type); 47 | 48 | ~ExceptionObj(); 49 | 50 | std::string to_string(bool colors = true) const; 51 | 52 | static std::string exception_message(vm::Exception expected); 53 | }; 54 | 55 | } 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /test/code/euler/pe017.leek: -------------------------------------------------------------------------------- 1 | function get(n) { 2 | if (n == 1) return "one" 3 | if (n == 2) return "two" 4 | if (n == 3) return "three" 5 | if (n == 4) return "four" 6 | if (n == 5) return "five" 7 | if (n == 6) return "six" 8 | if (n == 7) return "seven" 9 | if (n == 8) return "eight" 10 | if (n == 9) return "nine" 11 | if (n == 10) return "ten" 12 | if (n == 11) return "eleven" 13 | if (n == 12) return "twelve" 14 | if (n == 13) return "thirteen" 15 | if (n == 14) return "fourteen" 16 | if (n == 15) return "fifteen" 17 | if (n == 16) return "sixteen" 18 | if (n == 17) return "seventeen" 19 | if (n == 18) return "eighteen" 20 | if (n == 19) return "nineteen" 21 | 22 | if (n == 20) return "twenty" 23 | if (n == 30) return "thirty" 24 | if (n == 40) return "forty" 25 | if (n == 50) return "fifty" 26 | if (n == 60) return "sixty" 27 | if (n == 70) return "seventy" 28 | if (n == 80) return "eighty" 29 | if (n == 90) return "ninety" 30 | 31 | if (n < 100) { 32 | var diz = (n \ 10) * 10 33 | return get(diz) + get(n - diz) 34 | } 35 | 36 | if (n < 1000) { 37 | var cent = n \ 100 38 | var reste = n % 100 39 | var res = get(cent) + "hundred" 40 | if (reste > 0) { 41 | // TODO res += 42 | res = res + "and" + get(reste) 43 | } 44 | return res 45 | } 46 | return "onethousand" 47 | } 48 | 49 | var sum = 0 50 | for (var i = 1; i <= 1000; ++i) { 51 | sum += |get(i)| 52 | } 53 | 54 | sum -------------------------------------------------------------------------------- /src/type/Function_type.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FUNCTION_TYPE_HPP 2 | #define FUNCTION_TYPE_HPP 3 | 4 | #include "Type.hpp" 5 | 6 | namespace ls { 7 | 8 | class Type; 9 | class Value; 10 | 11 | class Function_type : public Type { 12 | #if COMPILER 13 | llvm::Type* llvm_type = nullptr; 14 | #endif 15 | const Type* const _return_type; 16 | std::vector _arguments; 17 | const Value* _function; 18 | public: 19 | bool closure() const { return false; } 20 | Function_type(const Type*, const std::vector&, const Value* function = nullptr); 21 | const Value* function() const override { return _function; } 22 | virtual int id() const override { return 9; } 23 | virtual const std::string getName() const override { return "function"; } 24 | virtual Json json() const override; 25 | virtual bool callable() const override { return true; } 26 | virtual bool operator == (const Type*) const override; 27 | virtual int distance(const Type* type) const override; 28 | virtual const Type* return_type() const override; 29 | virtual const std::vector& arguments() const override; 30 | virtual const Type* argument(size_t) const override; 31 | #if COMPILER 32 | virtual llvm::Type* llvm(Compiler& c) const override; 33 | #endif 34 | virtual std::string class_name() const override; 35 | virtual std::ostream& print(std::ostream& os) const override; 36 | virtual Type* clone() const override; 37 | }; 38 | 39 | } 40 | 41 | #endif -------------------------------------------------------------------------------- /src/vm/value/LSBoolean.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LSBOOLEAN_HPP_ 2 | #define LSBOOLEAN_HPP_ 3 | 4 | #include 5 | #include "../LSValue.hpp" 6 | 7 | namespace ls { 8 | 9 | class LSBoolean : public LSValue { 10 | private: 11 | 12 | LSBoolean(bool value); 13 | 14 | public: 15 | 16 | const bool value; 17 | 18 | static LSBoolean* false_val; 19 | static LSBoolean* true_val; 20 | static LSBoolean* create(bool value) { 21 | return new LSBoolean(value); 22 | } 23 | static LSBoolean* get(bool value) { 24 | return value ? true_val : false_val; 25 | } 26 | static void set_true_value(LSBoolean* v) { 27 | true_val = v; 28 | } 29 | static void set_false_value(LSBoolean* v) { 30 | false_val = v; 31 | } 32 | 33 | virtual ~LSBoolean(); 34 | 35 | bool to_bool() const override; 36 | bool ls_not() const override; 37 | LSValue* ls_tilde() override; 38 | LSValue* ls_minus() override; 39 | 40 | LSValue* add(LSValue* v) override; 41 | LSValue* sub(LSValue* v) override; 42 | bool eq(const LSValue*) const override; 43 | bool lt(const LSValue*) const override; 44 | bool operator < (int value) const override; 45 | bool operator < (double value) const override; 46 | 47 | int abso() const override; 48 | 49 | LSValue* clone() const override; 50 | 51 | std::ostream& dump(std::ostream& os, int level) const override; 52 | std::string json() const override; 53 | 54 | LSValue* getClass(VM* vm) const override; 55 | }; 56 | 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/analyzer/resolver/VirtualResolver.cpp: -------------------------------------------------------------------------------- 1 | #include "VirtualResolver.hpp" 2 | #include 3 | #include "../../util/Util.hpp" 4 | #include 5 | #include "../Program.hpp" 6 | #include "../../colors.h" 7 | 8 | namespace ls { 9 | 10 | static std::unordered_map> file_cache; 11 | 12 | File* VirtualResolver::create(std::string path, Program* program) const { 13 | auto fspath = std::filesystem::path(path); 14 | auto code = program ? program->code : ""; 15 | return file_cache.emplace(path, new File(path, code, FileContext(fspath.parent_path()), program)).first->second.get(); 16 | } 17 | 18 | File* VirtualResolver::delete_(std::string path) const { 19 | auto fspath = std::filesystem::path(path); 20 | auto file = file_cache[path].release(); 21 | file_cache.erase(path); 22 | return file; 23 | } 24 | 25 | File* VirtualResolver::resolve(std::string path, FileContext context) const { 26 | auto resolvedPath = (context.folder / path).lexically_normal(); 27 | auto i = file_cache.find(resolvedPath); 28 | if (i != file_cache.end()) { 29 | return i->second.get(); 30 | } 31 | // std::cout << "[" << C_YELLOW << "warning" << END_COLOR << "] Virtual file " << BOLD << resolvedPath << END_STYLE << " does not exist in context " << context.folder << std::endl; 32 | return nullptr; 33 | } 34 | 35 | std::unordered_map>& VirtualResolver::get_cache() { 36 | return file_cache; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /src/doc/Documentation.cpp: -------------------------------------------------------------------------------- 1 | #include "Documentation.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "../standard/class/ArraySTD.hpp" 8 | #include "../standard/class/MapSTD.hpp" 9 | #include "../standard/class/BooleanSTD.hpp" 10 | #include "../standard/class/NumberSTD.hpp" 11 | #include "../standard/class/ObjectSTD.hpp" 12 | #include "../standard/class/StringSTD.hpp" 13 | #include "../standard/class/IntervalSTD.hpp" 14 | #include "../standard/class/SetSTD.hpp" 15 | #include "../standard/class/SystemSTD.hpp" 16 | #include "../standard/class/ClassSTD.hpp" 17 | #include "../standard/class/FunctionSTD.hpp" 18 | #include "../standard/class/JsonSTD.hpp" 19 | #include "../standard/class/NullSTD.hpp" 20 | #include "../standard/class/ValueSTD.hpp" 21 | #include "../standard/StandardLibrary.hpp" 22 | #include "../environment/Environment.hpp" 23 | 24 | namespace ls { 25 | 26 | Documentation::Documentation() {} 27 | 28 | Documentation::~Documentation() {} 29 | 30 | void Documentation::generate(std::ostream& os, std::string lang) { 31 | 32 | Environment env; 33 | StandardLibrary stdLib { env }; 34 | 35 | os << "{"; 36 | 37 | int m = 0; 38 | for (const auto& clazz : stdLib.classes) { 39 | if (m > 0) os << ","; 40 | 41 | std::string file = "src/doc/" + clazz.second->name + "_" + lang + ".json"; 42 | 43 | clazz.second->generate_doc(os, file); 44 | m++; 45 | } 46 | 47 | os << "}\n"; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/vm/value/LSInterval.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VM_VALUE_LSINTERVAL_HPP_ 2 | #define VM_VALUE_LSINTERVAL_HPP_ 3 | 4 | #include "../LSValue.hpp" 5 | 6 | namespace ls { 7 | 8 | class LSFunction; 9 | 10 | class LSInterval : public LSValue { 11 | public: 12 | 13 | static LSInterval* constructor(int a, int b); 14 | 15 | int a = 0; 16 | int b = 0; 17 | 18 | LSInterval(); 19 | virtual ~LSInterval(); 20 | 21 | /* 22 | * Array methods 23 | */ 24 | template 25 | static LSArray* std_filter(LSInterval* interval, F function); 26 | static long std_sum(LSInterval* interval); 27 | static long std_product(LSInterval* interval); 28 | static int std_at_i_i(LSInterval* interval, const int key); 29 | static bool std_in_i(LSInterval* interval, const int); 30 | 31 | /* 32 | * LSValue methods 33 | */ 34 | virtual bool to_bool() const override; 35 | virtual bool ls_not() const override; 36 | virtual bool eq(const LSValue*) const override; 37 | virtual bool in(const LSValue* const) const override; 38 | virtual bool in_i(const int) const override; 39 | 40 | virtual LSValue* at(const LSValue* key) const override; 41 | int at_i_i(const int key) const override; 42 | LSValue* range(int start, int end) const override; 43 | virtual int abso() const override; 44 | 45 | virtual LSValue* clone() const override; 46 | virtual std::ostream& dump(std::ostream& os, int level) const override; 47 | LSValue* getClass(VM* vm) const override; 48 | }; 49 | 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/analyzer/instruction/Break.cpp: -------------------------------------------------------------------------------- 1 | #include "Break.hpp" 2 | #include "../semantic/SemanticAnalyzer.hpp" 3 | #include "../error/Error.hpp" 4 | 5 | namespace ls { 6 | 7 | Break::Break(Environment& env) : Instruction(env) { 8 | deepness = 1; 9 | jumping = true; 10 | jump_to_existing_section = true; 11 | breaking = true; 12 | } 13 | 14 | void Break::print(std::ostream& os, int, PrintOptions) const { 15 | os << "break"; 16 | if (deepness > 1) { 17 | os << " " << deepness; 18 | } 19 | } 20 | 21 | Location Break::location() const { 22 | return token->location; 23 | } 24 | 25 | void Break::analyze(SemanticAnalyzer* analyzer, const Type*) { 26 | 27 | // break must be in a loop 28 | if (!analyzer->in_loop(deepness)) { 29 | analyzer->add_error({Error::Type::BREAK_MUST_BE_IN_LOOP, ErrorLevel::ERROR, token->location, token->location}); 30 | } 31 | } 32 | 33 | #if COMPILER 34 | Compiler::value Break::compile(Compiler& c) const { 35 | /* { for { 36 | * let x = ... 37 | * { 38 | * let y = ... 39 | * if ... break => delete y, delete x, goto end 40 | * let z = ... 41 | * } 42 | * let w = ... 43 | * } 44 | * label end 45 | * } 46 | */ 47 | c.delete_variables_block(c.get_current_loop_blocks(deepness)); 48 | return { c.env }; 49 | } 50 | #endif 51 | 52 | std::unique_ptr Break::clone(Block* parent) const { 53 | auto b = std::make_unique(type->env); 54 | b->token = token; 55 | b->deepness = deepness; 56 | return b; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/vm/value/LSFunction.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LSFUNCTION_H_ 2 | #define LSFUNCTION_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "../LSValue.hpp" 8 | 9 | namespace ls { 10 | 11 | class VM; 12 | 13 | template R call(LSFunction* function, A... args); 14 | 15 | class LSFunction : public LSValue { 16 | public: 17 | 18 | static LSFunction* constructor(VM* vm, void* f); 19 | 20 | void* function; 21 | // For reflexion 22 | std::vector args; 23 | LSValue* return_type; 24 | 25 | LSFunction(void* function); 26 | virtual ~LSFunction(); 27 | virtual bool closure() const; 28 | 29 | static LSValue* call(LSFunction* function, LSValue* object, LSValue* arg1) { 30 | auto fun = (LSValue* (*)(LSValue*, LSValue*)) function->function; 31 | return fun(object, arg1); 32 | } 33 | 34 | /* 35 | * LSValue methods 36 | */ 37 | bool to_bool() const override; 38 | bool ls_not() const override; 39 | bool eq(const LSValue*) const override; 40 | bool lt(const LSValue*) const override; 41 | LSValue* attr(VM* vm, const std::string& key) const override; 42 | LSValue* clone() const override; 43 | std::ostream& dump(std::ostream& os, int level) const override; 44 | std::string json() const override; 45 | LSValue* getClass(VM* vm) const override; 46 | }; 47 | 48 | template R call(LSFunction* function, A... args) { 49 | auto fun = (R (*)(A...)) function->function; 50 | return fun(args...); 51 | } 52 | 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/analyzer/value/ArrayFor.cpp: -------------------------------------------------------------------------------- 1 | #include "ArrayFor.hpp" 2 | #include "../semantic/SemanticAnalyzer.hpp" 3 | 4 | namespace ls { 5 | 6 | ArrayFor::ArrayFor(Environment& env) : Value(env) { 7 | jumping = true; 8 | } 9 | 10 | void ArrayFor::print(std::ostream& os, int indent, PrintOptions options) const { 11 | os << "["; 12 | forr->print(os, indent, options); 13 | os << "]"; 14 | 15 | if (options.debug) { 16 | os << " " << type; 17 | } 18 | } 19 | 20 | Location ArrayFor::location() const { 21 | return {nullptr, {0, 0, 0}, {0, 0, 0}}; // TODO 22 | } 23 | 24 | Hover ArrayFor::hover(SemanticAnalyzer& analyzer, size_t position) const { 25 | if (forr->location().contains(position)) { 26 | return forr->hover(analyzer, position); 27 | } 28 | return { type, location() }; 29 | } 30 | 31 | void ArrayFor::pre_analyze(SemanticAnalyzer* analyzer) { 32 | forr->pre_analyze(analyzer); 33 | } 34 | 35 | void ArrayFor::analyze(SemanticAnalyzer* analyzer) { 36 | auto& env = analyzer->env; 37 | forr->analyze(analyzer, Type::array(env.void_)); 38 | type = forr->type; 39 | return_type = forr->return_type; 40 | throws = forr->throws; 41 | } 42 | 43 | #if COMPILER 44 | Compiler::value ArrayFor::compile(Compiler& c) const { 45 | return forr->compile(c); 46 | } 47 | #endif 48 | 49 | std::unique_ptr ArrayFor::clone(Block* parent) const { 50 | auto af = std::make_unique(type->env); 51 | af->forr = forr->clone(parent); 52 | af->end_section = af->forr->end_section; 53 | return af; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/analyzer/instruction/VariableDeclaration.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VARIABLEDECLARATION_HPP 2 | #define VARIABLEDECLARATION_HPP 3 | 4 | #include 5 | #include "Instruction.hpp" 6 | #include "../semantic/SemanticAnalyzer.hpp" 7 | 8 | namespace ls { 9 | 10 | class Variable; 11 | 12 | class VariableDeclaration : public Instruction { 13 | public: 14 | 15 | Token* keyword = nullptr; 16 | bool global = false; 17 | bool constant = false; 18 | bool function = false; 19 | std::vector variables; 20 | std::vector> expressions; 21 | std::map global_vars; 22 | std::map vars; 23 | 24 | VariableDeclaration(Environment& env); 25 | 26 | virtual void print(std::ostream&, int indent, PrintOptions options) const override; 27 | virtual Location location() const override; 28 | 29 | virtual void set_end_section(Section* end_section) override; 30 | 31 | void analyze_global_functions(SemanticAnalyzer* analyzer) const; 32 | virtual void pre_analyze(SemanticAnalyzer* analyzer) override; 33 | virtual void analyze(SemanticAnalyzer*, const Type* req_type) override; 34 | virtual Completion autocomplete(SemanticAnalyzer& analyzer, size_t position) const override; 35 | virtual Hover hover(SemanticAnalyzer& analyzer, size_t position) const override; 36 | 37 | #if COMPILER 38 | virtual Compiler::value compile(Compiler&) const override; 39 | #endif 40 | 41 | virtual std::unique_ptr clone(Block* parent) const override; 42 | }; 43 | 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/analyzer/semantic/Call.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CALL_HPP_ 2 | #define CALL_HPP_ 3 | 4 | #include 5 | #include 6 | #include "../../constants.h" 7 | #if COMPILER 8 | #include "../../compiler/Compiler.hpp" 9 | #endif 10 | 11 | namespace ls { 12 | 13 | class SemanticAnalyzer; 14 | class CallableVersion; 15 | class CallableVersionTemplate; 16 | class Callable; 17 | class Type; 18 | class Value; 19 | 20 | class Call { 21 | public: 22 | std::vector callables; 23 | const Value* value = nullptr; 24 | Value* object = nullptr; 25 | 26 | Call() {} 27 | Call(const Value* value) : value(value) {} 28 | Call(Callable* callable) : callables({ callable }) {} 29 | Call(Callable* callable, const Value* value, Value* object = nullptr) : callables({ callable }), value(value), object(object) {} 30 | Call(std::vector versions); 31 | void add_callable(Callable* callable); 32 | 33 | CallableVersion resolve(SemanticAnalyzer* analyzer, std::vector arguments) const; 34 | void apply_mutators(SemanticAnalyzer* analyzer, CallableVersion& version, std::vector arguments) const; 35 | #if COMPILER 36 | Compiler::value pre_compile_call(Compiler& c) const; 37 | Compiler::value compile_call(Compiler& c, const CallableVersion& version, std::vector args, int flags) const; 38 | #endif 39 | }; 40 | 41 | } 42 | 43 | namespace std { 44 | std::ostream& operator << (std::ostream&, const ls::Call&); 45 | std::ostream& operator << (std::ostream&, const ls::Call*); 46 | } 47 | 48 | #endif -------------------------------------------------------------------------------- /test/code/euler/pe008.leek: -------------------------------------------------------------------------------- 1 | let S = 2 | "73167176531330624919225119674426574742355349194934" + 3 | "96983520312774506326239578318016984801869478851843" + 4 | "85861560789112949495459501737958331952853208805511" + 5 | "12540698747158523863050715693290963295227443043557" + 6 | "66896648950445244523161731856403098711121722383113" + 7 | "62229893423380308135336276614282806444486645238749" + 8 | "30358907296290491560440772390713810515859307960866" + 9 | "70172427121883998797908792274921901699720888093776" + 10 | "65727333001053367881220235421809751254540594752243" + 11 | "52584907711670556013604839586446706324415722155397" + 12 | "53697817977846174064955149290862569321978468622482" + 13 | "83972241375657056057490261407972968652414535100474" + 14 | "82166370484403199890008895243450658541227588666881" + 15 | "16427171479924442928230863465674813919123162824586" + 16 | "17866458359124566529476545682848912883142607690042" + 17 | "24219022671055626321111109370544217506941658960408" + 18 | "07198403850962455444362981230987879927244284909188" + 19 | "84580156166097919133875499200524063689912560717606" + 20 | "05886116467109405077541002256983155200055935729725" + 21 | "71636269561882670428252483600823257530420752963450" 22 | 23 | var N = [] 24 | for var s in S.split('') { 25 | N += String.code(s) - String.code('0') 26 | } 27 | 28 | var max = 1l 29 | for var i = 0; i < N.size() - 12; ++i { 30 | var prod = N[i : i + 12].foldLeft((x, y -> x × y), 1.0) 31 | var prod_int = String.number('' + prod) 32 | if max < prod_int { 33 | max = prod_int 34 | } 35 | } 36 | return max 37 | -------------------------------------------------------------------------------- /src/vm/value/LSObject.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LSOBJECT_HPP_ 2 | #define LSOBJECT_HPP_ 3 | 4 | #include "../LSValue.hpp" 5 | 6 | namespace ls { 7 | 8 | class LSClass; 9 | 10 | class LSObject : public LSValue { 11 | public: 12 | static LSObject* constructor(); 13 | 14 | std::map values; 15 | LSClass* clazz; 16 | bool readonly; 17 | 18 | LSObject(); 19 | LSObject(LSClass*); 20 | virtual ~LSObject(); 21 | 22 | /** LSObject methods **/ 23 | void addField(const char* name, LSValue* value); 24 | static void std_add_field(LSObject* object, const char* name, LSValue* value); 25 | LSValue* getField(std::string name); 26 | static LSArray* ls_get_keys(const LSObject* const object); 27 | static LSArray* ls_get_values(const LSObject* const object); 28 | template 29 | static LSObject* ls_map(const LSObject* const object, F fun); 30 | static bool ls_in(const LSObject* const object, const LSValue* value); 31 | 32 | /** LSValue methods **/ 33 | bool to_bool() const override; 34 | bool ls_not() const override; 35 | bool eq(const LSValue*) const override; 36 | bool lt(const LSValue*) const override; 37 | bool in(const LSValue*) const override; 38 | LSValue* attr(VM* vm, const std::string& key) const override; 39 | LSValue** attrL(const std::string& key) override; 40 | int abso() const override; 41 | LSValue* clone() const override; 42 | std::ostream& dump(std::ostream& os, int level) const override; 43 | std::string json() const override; 44 | LSValue* getClass(VM* vm) const override; 45 | }; 46 | 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/type/String_type.cpp: -------------------------------------------------------------------------------- 1 | #include "String_type.hpp" 2 | #include "../colors.h" 3 | #include 4 | #include "Type.hpp" 5 | #include "Any_type.hpp" 6 | #include "Struct_type.hpp" 7 | #include "../environment/Environment.hpp" 8 | 9 | namespace ls { 10 | 11 | String_type::String_type(Environment& env) : Pointer_type(Type::structure("string", { 12 | env.integer, // ? 13 | env.integer, // ? 14 | env.integer, // ? 15 | env.integer, // refs 16 | env.boolean // native 17 | })) {} 18 | 19 | const Type* String_type::key() const { 20 | return env.integer; 21 | } 22 | const Type* String_type::element() const { 23 | return env.string; 24 | } 25 | const Type* String_type::iterator() const { 26 | return Type::structure("string_iterator", { 27 | env.any, env.integer, env.integer, env.integer, env.integer 28 | }); 29 | } 30 | bool String_type::operator == (const Type* type) const { 31 | return dynamic_cast(type); 32 | } 33 | int String_type::distance(const Type* type) const { 34 | if (not temporary and type->temporary) return -1; 35 | if (dynamic_cast(type->folded)) { return 1; } 36 | if (dynamic_cast(type->folded)) { return 0; } 37 | return -1; 38 | } 39 | std::string String_type::class_name() const { 40 | return "String"; 41 | } 42 | Json String_type::json() const { 43 | return { 44 | { "name", "string" } 45 | }; 46 | } 47 | std::ostream& String_type::print(std::ostream& os) const { 48 | os << BLUE_BOLD << "string" << END_COLOR; 49 | return os; 50 | } 51 | Type* String_type::clone() const { 52 | return new String_type { env }; 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /src/type/Interval_type.cpp: -------------------------------------------------------------------------------- 1 | #include "Interval_type.hpp" 2 | #include "../colors.h" 3 | #include "Type.hpp" 4 | #include "Any_type.hpp" 5 | #include "Struct_type.hpp" 6 | #include "../environment/Environment.hpp" 7 | 8 | namespace ls { 9 | 10 | Interval_type::Interval_type(Environment& env) : Pointer_type(Type::structure("interval", { 11 | env.integer, // ? 12 | env.integer, // ? 13 | env.integer, // ? 14 | env.integer, // ? 15 | env.boolean, // native 16 | env.integer, // A 17 | env.integer // B 18 | })) {} 19 | 20 | const Type* Interval_type::key() const { 21 | return env.integer; 22 | } 23 | const Type* Interval_type::element() const { 24 | return env.integer; 25 | } 26 | const Type* Interval_type::iterator() const { 27 | return Type::structure("interval_iterator", { 28 | env.interval, env.integer 29 | }); 30 | } 31 | bool Interval_type::operator == (const Type* type) const { 32 | return dynamic_cast(type); 33 | } 34 | int Interval_type::distance(const Type* type) const { 35 | if (not temporary and type->temporary) return -1; 36 | if (dynamic_cast(type->folded)) { return 1; } 37 | if (dynamic_cast(type->folded)) { return 0; } 38 | return -1; 39 | } 40 | std::string Interval_type::class_name() const { 41 | return "Interval"; 42 | } 43 | Json Interval_type::json() const { 44 | return { 45 | { "name", "interval" } 46 | }; 47 | } 48 | std::ostream& Interval_type::print(std::ostream& os) const { 49 | os << BLUE_BOLD << "interval" << END_COLOR; 50 | return os; 51 | } 52 | Type* Interval_type::clone() const { 53 | return new Interval_type { env }; 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /src/standard/StandardLibrary.cpp: -------------------------------------------------------------------------------- 1 | #include "StandardLibrary.hpp" 2 | #include "class/ValueSTD.hpp" 3 | #include "class/NullSTD.hpp" 4 | #include "class/NumberSTD.hpp" 5 | #include "class/BooleanSTD.hpp" 6 | #include "class/StringSTD.hpp" 7 | #include "class/ArraySTD.hpp" 8 | #include "class/MapSTD.hpp" 9 | #include "class/SetSTD.hpp" 10 | #include "class/ObjectSTD.hpp" 11 | #include "class/SystemSTD.hpp" 12 | #include "class/FunctionSTD.hpp" 13 | #include "class/ClassSTD.hpp" 14 | #include "class/IntervalSTD.hpp" 15 | #include "class/JsonSTD.hpp" 16 | #if COMPILER 17 | #include "../vm/value/LSNumber.hpp" 18 | #include "../vm/value/LSObject.hpp" 19 | #endif 20 | 21 | namespace ls { 22 | 23 | StandardLibrary::StandardLibrary(Environment& env, bool legacy) : env(env), legacy(legacy) { 24 | add_class(std::make_unique(env)); 25 | add_class(std::make_unique(env)); 26 | add_class(std::make_unique(env)); 27 | add_class(std::make_unique(env)); 28 | add_class(std::make_unique(env)); 29 | add_class(std::make_unique(env)); 30 | add_class(std::make_unique(env)); 31 | add_class(std::make_unique(env)); 32 | add_class(std::make_unique(env)); 33 | add_class(std::make_unique(env)); 34 | add_class(std::make_unique(env)); 35 | if (not legacy) { 36 | add_class(std::make_unique(env)); 37 | add_class(std::make_unique(env)); 38 | add_class(std::make_unique(env)); 39 | } 40 | } 41 | 42 | void StandardLibrary::add_class(std::unique_ptr m) { 43 | classes.insert({ m->name, std::move(m) }); 44 | } 45 | 46 | } --------------------------------------------------------------------------------