diff --git a/docs/build.gradle b/docs/build.gradle index 9b9b905..f5f694d 100644 --- a/docs/build.gradle +++ b/docs/build.gradle @@ -1,3 +1,21 @@ +plugins { + id 'java' +} + +group = 'com.annimon' +version = '2.0-SNAPSHOT' + +dependencies { + implementation project(":ownlang-core") + implementation project(":ownlang-parser") + implementation project(":ownlang-utils") + implementation project(":modules:main") + implementation project(":modules:canvasfx") + implementation project(":modules:server") + + implementation "org.yaml:snakeyaml:${versions.snakeyaml}" +} + tasks.register('generateMarkdownModules') { group = "documentation" def ownlangExec = tasks.getByPath(':ownlang-desktop:ownlangExec') @@ -8,4 +26,13 @@ tasks.register('generateMarkdownModules') { } } finalizedBy ownlangExec +} + +tasks.register('generateModuleInfo', JavaExec) { + group = "documentation" + description = "Run sample program" + dependsOn classes + mainClass = 'com.annimon.ownlang.docs.ModulesInfoCreator' + classpath = sourceSets.main.runtimeClasspath + args 'server', 'okhttp' } \ No newline at end of file diff --git a/docs/src/main/java/com/annimon/ownlang/docs/ModuleInfo.java b/docs/src/main/java/com/annimon/ownlang/docs/ModuleInfo.java new file mode 100644 index 0000000..bc3f522 --- /dev/null +++ b/docs/src/main/java/com/annimon/ownlang/docs/ModuleInfo.java @@ -0,0 +1,80 @@ +package com.annimon.ownlang.docs; + +import com.annimon.ownlang.Version; +import com.annimon.ownlang.lib.MapValue; +import com.annimon.ownlang.lib.Types; +import com.annimon.ownlang.lib.Value; +import java.util.*; +import java.util.stream.Collectors; + +public class ModuleInfo { + private final String name; + final List functions; + final Map constants; + final List types; + + public ModuleInfo(String name) { + this.name = name; + functions = new ArrayList<>(); + constants = new HashMap<>(); + types = new ArrayList<>(); + } + + public List> functions() { + return functions.stream().sorted() + .map(f -> { + final Map function = new LinkedHashMap<>(); + function.put("name", f); + function.put("args", ""); + function.put("desc", ""); + function.put("desc_ru", ""); + return function; + }) + .collect(Collectors.toList()); + } + + public List> constants() { + final List> result = new ArrayList<>(); + constants.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(entry -> { + final Value value = entry.getValue(); + + final Map constant = new LinkedHashMap<>(); + constant.put("name", entry.getKey()); + constant.put("type", value.type()); + constant.put("typeName", Types.typeToString(value.type())); + if (value.type() == Types.MAP) { + String text = ((MapValue) value).getMap().entrySet().stream() + .sorted(Comparator.comparing( + e -> ((MapValue) value).size() > 16 ? e.getKey() : e.getValue())) + .map(Object::toString) + .collect(Collectors.joining(", ", "{", "}")); + constant.put("value", text); + } else { + constant.put("value", value.asString()); + } + result.add(constant); + }); + return result; + } + + public Map info() { + final Map result = new LinkedHashMap<>(); + result.put("name", name); + result.put("scope", "both"); + result.put("since", "%d.%d.%d".formatted(Version.VERSION_MAJOR, Version.VERSION_MINOR, Version.VERSION_PATCH)); + result.put("constants", constants()); + result.put("functions", functions()); + if (!types.isEmpty()) { + result.put("types", types.stream().sorted() + .map(s -> { + final Map type = new HashMap<>(); + type.put("name", s); + return type; + }) + .toArray()); + } + return result; + } +} \ No newline at end of file diff --git a/docs/src/main/java/com/annimon/ownlang/docs/ModulesInfoCreator.java b/docs/src/main/java/com/annimon/ownlang/docs/ModulesInfoCreator.java new file mode 100644 index 0000000..d54982e --- /dev/null +++ b/docs/src/main/java/com/annimon/ownlang/docs/ModulesInfoCreator.java @@ -0,0 +1,73 @@ +package com.annimon.ownlang.docs; + +import com.annimon.ownlang.lib.ModuleLoader; +import com.annimon.ownlang.lib.Value; +import com.annimon.ownlang.modules.Module; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class ModulesInfoCreator { + + public static void main(String[] args) { + if (args.length == 0) { + System.err.println("No modules provided.\nUsage: ModulesInfoCreator ..."); + System.exit(1); + } + + final Class clazz = Module.class; // get classloader for package + + final List moduleInfos = new ArrayList<>(); + + for (String moduleName : args) { + final Module module = ModuleLoader.load(moduleName); + + final ModuleInfo moduleInfo = new ModuleInfo(moduleName); + moduleInfo.functions.addAll(module.functions().keySet()); + moduleInfo.constants.putAll(module.constants()); + moduleInfo.types.addAll(listValues(module.getClass())); + moduleInfos.add(moduleInfo); + } + + printAsYaml(moduleInfos); + + System.out.println("Total functions: " + moduleInfos.stream() + .mapToLong(m -> m.functions.size()) + .sum() + ); + System.out.println("Total constants: " + moduleInfos.stream() + .mapToLong(m -> m.constants.keySet().size()) + .sum() + ); + } + + private static void printAsYaml(List moduleInfos) { + DumperOptions options = new DumperOptions(); + options.setIndent(2); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + + final List> infos = new ArrayList<>(); + for (ModuleInfo moduleInfo : moduleInfos) { + infos.add(moduleInfo.info()); + } + System.out.println(new Yaml(options).dump(infos)); + } + + private static List listValues(Class moduleClass) { + return Arrays.stream(moduleClass.getDeclaredClasses()) + .filter(clazz -> getAllInterfaces(clazz).stream().anyMatch(i -> i.equals(Value.class))) + .map(Class::getSimpleName) + .collect(Collectors.toList()); + } + + private static Set> getAllInterfaces(Class clazz) { + if (clazz.getSuperclass() == null) { + return Collections.emptySet(); + } + return Stream.concat(Arrays.stream(clazz.getInterfaces()), getAllInterfaces(clazz.getSuperclass()).stream()) + .collect(Collectors.toSet()); + } + +} diff --git a/ownlang-utils/build.gradle b/ownlang-utils/build.gradle index 8a12b43..205d0bf 100644 --- a/ownlang-utils/build.gradle +++ b/ownlang-utils/build.gradle @@ -7,8 +7,6 @@ version = '2.0-SNAPSHOT' dependencies { api project(":ownlang-parser") - implementation "org.json:json:${versions.json}" - implementation "org.yaml:snakeyaml:${versions.snakeyaml}" implementation "jline:jline:${versions.jline}" testImplementation platform("org.junit:junit-bom:${versions.junit}") diff --git a/ownlang-utils/src/main/java/com/annimon/ownlang/utils/ModulesInfoCreator.java b/ownlang-utils/src/main/java/com/annimon/ownlang/utils/ModulesInfoCreator.java deleted file mode 100644 index de6447a..0000000 --- a/ownlang-utils/src/main/java/com/annimon/ownlang/utils/ModulesInfoCreator.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.annimon.ownlang.utils; - -import com.annimon.ownlang.lib.*; -import com.annimon.ownlang.modules.Module; -import java.io.File; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.json.JSONArray; -import org.json.JSONObject; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.Yaml; - -public final class ModulesInfoCreator { - - private static final String MODULES_PATH = "src/main/java/com/annimon/ownlang/modules"; - - public static void main(String[] args) - throws ReflectiveOperationException { - final Class clazz = Module.class; // get classloader for package - - final List moduleInfos = new ArrayList<>(); - - String[] moduleNames = Optional.ofNullable(new File(MODULES_PATH).listFiles()) - .stream() - .flatMap(Arrays::stream) - .filter(File::isDirectory) - .map(File::getName) - .toArray(String[]::new); - for (String moduleName : moduleNames) { - final Module module = ModuleLoader.load(moduleName); - - final ModuleInfo moduleInfo = new ModuleInfo(moduleName); - moduleInfo.functions.addAll(module.functions().keySet()); - moduleInfo.constants.putAll(module.constants()); - moduleInfo.types.addAll(listValues(module.getClass())); - moduleInfos.add(moduleInfo); - } - - // printAsJson(moduleInfos); - printAsYaml(moduleInfos); - - System.out.println("Total modules: " + moduleInfos.size()); - System.out.println("Total functions: " + moduleInfos.stream() - .mapToLong(m -> m.functions.size()) - .sum() - ); - System.out.println("Total constants: " + moduleInfos.stream() - .mapToLong(m -> m.constants.keySet().size()) - .sum() - ); - } - - private static void printAsJson(List moduleInfos) { - final JSONArray modulesJson = new JSONArray(); - for (ModuleInfo moduleInfo : moduleInfos) { - modulesJson.put(new JSONObject(moduleInfo.info())); - } - System.out.println(modulesJson.toString(2)); - } - - private static void printAsYaml(List moduleInfos) { - DumperOptions options = new DumperOptions(); - options.setIndent(2); - options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - - final List> infos = new ArrayList<>(); - for (ModuleInfo moduleInfo : moduleInfos) { - infos.add(moduleInfo.info()); - } - System.out.println(new Yaml(options).dump(infos)); - } - - private static List listValues(Class moduleClass) { - return Arrays.stream(moduleClass.getDeclaredClasses()) - .filter(clazz -> getAllInterfaces(clazz).stream().anyMatch(i -> i.equals(Value.class))) - .map(Class::getSimpleName) - .collect(Collectors.toList()); - } - - private static Set> getAllInterfaces(Class clazz) { - if (clazz.getSuperclass() == null) { - return Collections.emptySet(); - } - return Stream.concat(Arrays.stream(clazz.getInterfaces()), getAllInterfaces(clazz.getSuperclass()).stream()) - .collect(Collectors.toSet()); - } - - static class ModuleInfo { - private final String name; - final List functions; - final Map constants; - final List types; - - public ModuleInfo(String name) { - this.name = name; - functions = new ArrayList<>(); - constants = new HashMap<>(); - types = new ArrayList<>(); - } - - public List> functions() { - return functions.stream().sorted() - .map(f -> { - final Map function = new LinkedHashMap<>(); - function.put("name", f); - function.put("args", ""); - function.put("desc", ""); - function.put("desc_ru", ""); - return function; - }) - .collect(Collectors.toList()); - } - - public List> constants() { - final List> result = new ArrayList<>(); - constants.entrySet().stream() - .sorted(Map.Entry.comparingByKey()) - .forEach(entry -> { - final Value value = entry.getValue(); - - final Map constant = new LinkedHashMap<>(); - constant.put("name", entry.getKey()); - constant.put("type", value.type()); - constant.put("typeName", Types.typeToString(value.type())); - if (value.type() == Types.MAP) { - String text = ((MapValue) value).getMap().entrySet().stream() - .sorted(Comparator.comparing( - e -> ((MapValue)value).size() > 16 ? e.getKey() : e.getValue())) - .map(Object::toString) - .collect(Collectors.joining(", ", "{", "}")); - constant.put("value", text); - } else { - constant.put("value", value.asString()); - } - result.add(constant); - }); - return result; - } - - public Map info() { - final Map result = new LinkedHashMap<>(); - result.put("name", name); - result.put("scope", "both"); - result.put("constants", constants()); - result.put("functions", functions()); - if (!types.isEmpty()) { - result.put("types", types.stream().sorted() - .map(s -> { - final Map type = new HashMap<>(); - type.put("name", s); - return type; - }) - .toArray()); - } - return result; - } - } -} diff --git a/ownlang-utils/src/main/java/com/annimon/ownlang/utils/Sandbox.java b/ownlang-utils/src/main/java/com/annimon/ownlang/utils/Sandbox.java index b36659d..773882b 100644 --- a/ownlang-utils/src/main/java/com/annimon/ownlang/utils/Sandbox.java +++ b/ownlang-utils/src/main/java/com/annimon/ownlang/utils/Sandbox.java @@ -9,7 +9,6 @@ import com.annimon.ownlang.parser.Parser; import com.annimon.ownlang.parser.SourceLoader; import com.annimon.ownlang.parser.Token; import com.annimon.ownlang.parser.ast.Node; -import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.visitors.FunctionAdder; import java.io.File; import java.io.IOException;