mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Значительные исправления
This commit is contained in:
parent
be9bdb0311
commit
c7dd50c9ad
@ -36,6 +36,7 @@ task generateJavaSources() {
|
||||
def source = """
|
||||
package com.annimon.ownlang;
|
||||
class Gen {
|
||||
private Gen() {}
|
||||
public static final String BUILD_DATE = "${new Date().format('YYMMdd')}";
|
||||
}
|
||||
"""
|
||||
|
@ -50,9 +50,9 @@ public class Console {
|
||||
public static void handleException(Thread thread, Throwable throwable) {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try(final PrintStream ps = new PrintStream(baos)) {
|
||||
ps.printf("%s in %s\n", throwable.getMessage(), thread.getName());
|
||||
ps.printf("%s in %s%n", throwable.getMessage(), thread.getName());
|
||||
for (CallStack.CallInfo call : CallStack.getCalls()) {
|
||||
ps.printf("\tat %s\n", call);
|
||||
ps.printf("\tat %s%n", call);
|
||||
}
|
||||
ps.println();
|
||||
throwable.printStackTrace(ps);
|
||||
@ -74,4 +74,6 @@ public class Console {
|
||||
}
|
||||
return new File(filepath);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -33,25 +33,9 @@ public final class Main {
|
||||
public static void main(String[] args) throws IOException {
|
||||
if (args.length == 0) {
|
||||
try {
|
||||
final Options options = new Options();
|
||||
options.showAst = false;
|
||||
options.showTokens = false;
|
||||
options.showMeasurements = false;
|
||||
options.lintMode = false;
|
||||
options.optimizationLevel = 0;
|
||||
run(SourceLoader.readSource("program.own"), options);
|
||||
runDefault();
|
||||
} catch (IOException ioe) {
|
||||
System.out.println("OwnLang version " + VERSION + "\n\n" +
|
||||
"Usage: ownlang [options]\n" +
|
||||
" options:\n" +
|
||||
" -f, --file [input] Run program file. Required.\n" +
|
||||
" -r, --repl Enter to a REPL mode\n" +
|
||||
" -l, --lint Find bugs in code\n" +
|
||||
" -o N, --optimize N Perform optimization with N passes\n" +
|
||||
" -b, --beautify Beautify source code\n" +
|
||||
" -a, --showast Show AST of program\n" +
|
||||
" -t, --showtokens Show lexical tokens\n" +
|
||||
" -m, --showtime Show elapsed time of parsing and execution");
|
||||
printUsage();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -139,6 +123,30 @@ public final class Main {
|
||||
run(input, options);
|
||||
}
|
||||
|
||||
private static void runDefault() throws IOException {
|
||||
final Options options = new Options();
|
||||
options.showAst = false;
|
||||
options.showTokens = false;
|
||||
options.showMeasurements = false;
|
||||
options.lintMode = false;
|
||||
options.optimizationLevel = 0;
|
||||
run(SourceLoader.readSource("program.own"), options);
|
||||
}
|
||||
|
||||
private static void printUsage() {
|
||||
System.out.println("OwnLang version " + VERSION + "\n\n" +
|
||||
"Usage: ownlang [options]\n" +
|
||||
" options:\n" +
|
||||
" -f, --file [input] Run program file. Required.\n" +
|
||||
" -r, --repl Enter to a REPL mode\n" +
|
||||
" -l, --lint Find bugs in code\n" +
|
||||
" -o N, --optimize N Perform optimization with N passes\n" +
|
||||
" -b, --beautify Beautify source code\n" +
|
||||
" -a, --showast Show AST of program\n" +
|
||||
" -t, --showtokens Show lexical tokens\n" +
|
||||
" -m, --showtime Show elapsed time of parsing and execution");
|
||||
}
|
||||
|
||||
private static void createOwnLangArgs(String[] javaArgs, int index) {
|
||||
if (index >= javaArgs.length) return;
|
||||
ownlangArgs = new String[javaArgs.length - index];
|
||||
@ -152,7 +160,8 @@ public final class Main {
|
||||
final List<Token> tokens = Lexer.tokenize(input);
|
||||
measurement.stop("Tokenize time");
|
||||
if (options.showTokens) {
|
||||
for (int i = 0; i < tokens.size(); i++) {
|
||||
final int tokensCount = tokens.size();
|
||||
for (int i = 0; i < tokensCount; i++) {
|
||||
System.out.println(i + " " + tokens.get(i));
|
||||
}
|
||||
}
|
||||
@ -205,7 +214,7 @@ public final class Main {
|
||||
boolean lintMode;
|
||||
int optimizationLevel;
|
||||
|
||||
public Options() {
|
||||
Options() {
|
||||
showTokens = false;
|
||||
showAst = false;
|
||||
showMeasurements = false;
|
||||
@ -213,8 +222,8 @@ public final class Main {
|
||||
optimizationLevel = 0;
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
if (lintMode == true) {
|
||||
void validate() {
|
||||
if (lintMode) {
|
||||
showTokens = false;
|
||||
showAst = false;
|
||||
showMeasurements = false;
|
||||
|
@ -4,6 +4,8 @@ import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
|
||||
|
||||
public final class Arguments {
|
||||
|
||||
private Arguments() { }
|
||||
|
||||
public static void check(int expected, int got) {
|
||||
if (got != expected) throw new ArgumentsMismatchException(String.format(
|
||||
"%d %s expected, got %d", expected, pluralize(expected), got));
|
||||
|
@ -5,7 +5,9 @@ import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
|
||||
public final class CallStack {
|
||||
|
||||
private static final Deque<CallInfo> calls = new ConcurrentLinkedDeque<CallInfo>();;
|
||||
private static final Deque<CallInfo> calls = new ConcurrentLinkedDeque<>();
|
||||
|
||||
private CallStack() { }
|
||||
|
||||
public static synchronized void clear() {
|
||||
calls.clear();
|
||||
|
@ -15,6 +15,8 @@ public final class Functions {
|
||||
functions = new HashMap<>();
|
||||
}
|
||||
|
||||
private Functions() { }
|
||||
|
||||
public static void clear() {
|
||||
functions.clear();
|
||||
}
|
||||
|
@ -6,10 +6,15 @@ package com.annimon.ownlang.lib;
|
||||
*/
|
||||
public final class NumberValue implements Value {
|
||||
|
||||
public static final NumberValue MINUS_ONE, ZERO, ONE;
|
||||
private static final int CACHE_MIN = -128;
|
||||
private static final int CACHE_MAX = 127;
|
||||
|
||||
public static final NumberValue MINUS_ONE;
|
||||
public static final NumberValue ZERO;
|
||||
public static final NumberValue ONE;
|
||||
|
||||
private static final int CACHE_MIN = -128, CACHE_MAX = 127;
|
||||
private static final NumberValue[] NUMBER_CACHE;
|
||||
|
||||
static {
|
||||
final int length = CACHE_MAX - CACHE_MIN + 1;
|
||||
NUMBER_CACHE = new NumberValue[length];
|
||||
|
@ -10,7 +10,8 @@ public final class Types {
|
||||
MAP = 4,
|
||||
FUNCTION = 5;
|
||||
|
||||
private static final int FIRST = OBJECT, LAST = FUNCTION;
|
||||
private static final int FIRST = OBJECT;
|
||||
private static final int LAST = FUNCTION;
|
||||
private static final String[] NAMES = {"object", "number", "string", "array", "map", "function"};
|
||||
|
||||
public static String typeToString(int type) {
|
||||
@ -19,4 +20,6 @@ public final class Types {
|
||||
}
|
||||
return "unknown (" + type + ")";
|
||||
}
|
||||
|
||||
private Types() { }
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import org.json.JSONObject;
|
||||
|
||||
public final class ValueUtils {
|
||||
|
||||
private ValueUtils() { }
|
||||
|
||||
public static Object toObject(Value val) {
|
||||
switch (val.type()) {
|
||||
case Types.ARRAY:
|
||||
@ -101,7 +103,7 @@ public final class ValueUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Function consumeFunction(Value value, int argumentNumber) throws TypeException {
|
||||
public static Function consumeFunction(Value value, int argumentNumber) {
|
||||
final int type = value.type();
|
||||
if (type != Types.FUNCTION) {
|
||||
throw new TypeException("Function expected at argument " + (argumentNumber + 1)
|
||||
|
@ -35,6 +35,8 @@ public final class Variables {
|
||||
Variables.clear();
|
||||
}
|
||||
|
||||
private Variables() { }
|
||||
|
||||
public static Map<String, Value> variables() {
|
||||
return scope.variables;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ public final class canvasfx implements Module {
|
||||
private static GraphicsContext graphics;
|
||||
private static Canvas canvas;
|
||||
|
||||
private static enum Events {
|
||||
private enum Events {
|
||||
DRAG_DETECTED(MouseEvent.DRAG_DETECTED),
|
||||
MOUSE_CLICKED(MouseEvent.MOUSE_CLICKED),
|
||||
MOUSE_DRAGGED(MouseEvent.MOUSE_DRAGGED),
|
||||
|
@ -156,7 +156,7 @@ public final class files implements Module {
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class FileFunction implements Function {
|
||||
private abstract static class FileFunction implements Function {
|
||||
|
||||
@Override
|
||||
public Value execute(Value... args) {
|
||||
@ -252,7 +252,7 @@ public final class files implements Module {
|
||||
private static class setExecutable extends FileFunction {
|
||||
@Override
|
||||
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
||||
final boolean ownerOnly = (args.length >= 3) ? (args[2].asInt() != 0) : true;
|
||||
final boolean ownerOnly = (args.length < 3) || (args[2].asInt() != 0);
|
||||
return NumberValue.fromBoolean(
|
||||
fileInfo.file.setExecutable(args[1].asInt() != 0, ownerOnly));
|
||||
}
|
||||
@ -261,7 +261,7 @@ public final class files implements Module {
|
||||
private static class setReadable extends FileFunction {
|
||||
@Override
|
||||
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
||||
final boolean ownerOnly = (args.length >= 3) ? (args[2].asInt() != 0) : true;
|
||||
final boolean ownerOnly = (args.length < 3) || (args[2].asInt() != 0);
|
||||
return NumberValue.fromBoolean(
|
||||
fileInfo.file.setReadable(args[1].asInt() != 0, ownerOnly));
|
||||
}
|
||||
@ -270,7 +270,7 @@ public final class files implements Module {
|
||||
private static class setWritable extends FileFunction {
|
||||
@Override
|
||||
protected Value execute(FileInfo fileInfo, Value[] args) throws IOException {
|
||||
final boolean ownerOnly = (args.length >= 3) ? (args[2].asInt() != 0) : true;
|
||||
final boolean ownerOnly = (args.length < 3) || (args[2].asInt() != 0);
|
||||
return NumberValue.fromBoolean(
|
||||
fileInfo.file.setWritable(args[1].asInt() != 0, ownerOnly));
|
||||
}
|
||||
|
@ -14,7 +14,9 @@ import javax.swing.SwingConstants;
|
||||
*/
|
||||
public final class Components {
|
||||
|
||||
public static Value newWindow(Value... args) {
|
||||
private Components() { }
|
||||
|
||||
static Value newWindow(Value... args) {
|
||||
Arguments.checkOrOr(0, 1, args.length);
|
||||
String title = (args.length == 1) ? args[0].asString() : "";
|
||||
final JFrame frame = new JFrame(title);
|
||||
@ -22,7 +24,7 @@ public final class Components {
|
||||
return new JFrameValue(frame);
|
||||
}
|
||||
|
||||
public static Value newPanel(Value... args) {
|
||||
static Value newPanel(Value... args) {
|
||||
Arguments.checkOrOr(0, 1, args.length);
|
||||
final JPanel panel = new JPanel();
|
||||
if (args.length == 1) {
|
||||
@ -31,20 +33,20 @@ public final class Components {
|
||||
return new JPanelValue(panel);
|
||||
}
|
||||
|
||||
public static Value newButton(Value... args) {
|
||||
static Value newButton(Value... args) {
|
||||
Arguments.checkOrOr(0, 1, args.length);
|
||||
String text = (args.length == 1) ? args[0].asString() : "";
|
||||
return new JButtonValue(new JButton(text));
|
||||
}
|
||||
|
||||
public static Value newLabel(Value... args) {
|
||||
static Value newLabel(Value... args) {
|
||||
Arguments.checkRange(0, 2, args.length);
|
||||
String text = (args.length >= 1) ? args[0].asString() : "";
|
||||
int align = (args.length == 2) ? args[1].asInt() : SwingConstants.LEADING;
|
||||
return new JLabelValue(new JLabel(text, align));
|
||||
}
|
||||
|
||||
public static Value newTextField(Value... args) {
|
||||
static Value newTextField(Value... args) {
|
||||
Arguments.checkOrOr(0, 1, args.length);
|
||||
String text = (args.length == 1) ? args[0].asString() : "";
|
||||
return new JTextFieldValue(new JTextField(text));
|
||||
|
@ -13,7 +13,9 @@ import javax.swing.BoxLayout;
|
||||
*/
|
||||
public final class LayoutManagers {
|
||||
|
||||
public static Value borderLayout(Value... args) {
|
||||
private LayoutManagers() { }
|
||||
|
||||
static Value borderLayout(Value... args) {
|
||||
Arguments.checkOrOr(0, 2, args.length);
|
||||
int hgap = (args.length == 2) ? args[0].asInt() : 0;
|
||||
int vgap = (args.length == 2) ? args[1].asInt() : 0;
|
||||
@ -22,7 +24,7 @@ public final class LayoutManagers {
|
||||
);
|
||||
}
|
||||
|
||||
public static Value boxLayout(Value... args) {
|
||||
static Value boxLayout(Value... args) {
|
||||
Arguments.checkOrOr(1, 2, args.length);
|
||||
int axis = (args.length == 2) ? args[1].asInt() : BoxLayout.PAGE_AXIS;
|
||||
return new LayoutManagerValue(
|
||||
@ -30,7 +32,7 @@ public final class LayoutManagers {
|
||||
);
|
||||
}
|
||||
|
||||
public static Value cardLayout(Value... args) {
|
||||
static Value cardLayout(Value... args) {
|
||||
Arguments.checkOrOr(0, 2, args.length);
|
||||
int hgap = (args.length == 2) ? args[0].asInt() : 0;
|
||||
int vgap = (args.length == 2) ? args[1].asInt() : 0;
|
||||
@ -39,7 +41,7 @@ public final class LayoutManagers {
|
||||
);
|
||||
}
|
||||
|
||||
public static Value gridLayout(Value... args) {
|
||||
static Value gridLayout(Value... args) {
|
||||
Arguments.checkRange(0, 4, args.length);
|
||||
int rows = 1, cols = 0, hgap = 0, vgap = 0;
|
||||
switch (args.length) {
|
||||
@ -67,7 +69,7 @@ public final class LayoutManagers {
|
||||
);
|
||||
}
|
||||
|
||||
public static Value flowLayout(Value... args) {
|
||||
static Value flowLayout(Value... args) {
|
||||
Arguments.checkRange(0, 3, args.length);
|
||||
final int align, hgap, vgap;
|
||||
switch (args.length) {
|
||||
|
@ -36,7 +36,7 @@ public final class functional_filter implements Function {
|
||||
|
||||
private Value filterArray(ArrayValue array, Function predicate, boolean takeWhile) {
|
||||
final int size = array.size();
|
||||
final List<Value> values = new ArrayList<Value>(size);
|
||||
final List<Value> values = new ArrayList<>(size);
|
||||
for (Value value : array) {
|
||||
if (predicate.execute(value) != NumberValue.ZERO) {
|
||||
values.add(value);
|
||||
|
@ -144,9 +144,10 @@ public final class http_http implements Function {
|
||||
return getStringRequestBody(params, options);
|
||||
}
|
||||
|
||||
private RequestBody getMapRequestBody(MapValue params, MapValue options) throws UnsupportedEncodingException {
|
||||
private RequestBody getMapRequestBody(MapValue params, MapValue options) {
|
||||
final FormBody.Builder form = new FormBody.Builder();
|
||||
final boolean alreadyEncoded = (options.containsKey(ENCODED_KEY) && options.get(ENCODED_KEY).asInt() != 0);
|
||||
final boolean alreadyEncoded = (options.containsKey(ENCODED_KEY)
|
||||
&& options.get(ENCODED_KEY).asInt() != 0);
|
||||
for (Map.Entry<Value, Value> param : params) {
|
||||
final String name = param.getKey().asString();
|
||||
final String value = param.getValue().asString();
|
||||
|
@ -283,7 +283,7 @@ public final class java implements Module {
|
||||
methods.add(method);
|
||||
}
|
||||
}
|
||||
if (methods.size() == 0) {
|
||||
if (methods.isEmpty()) {
|
||||
return FunctionValue.EMPTY;
|
||||
}
|
||||
return new FunctionValue(methodsToFunction(object, methods));
|
||||
@ -362,7 +362,7 @@ public final class java implements Module {
|
||||
}
|
||||
|
||||
private static Value objectToValue(Class<?> clazz, Object o) {
|
||||
if (o == null | o == NULL) return NULL;
|
||||
if (o == null || o == NULL) return NULL;
|
||||
if (clazz.isPrimitive()) {
|
||||
if (int.class.isAssignableFrom(clazz))
|
||||
return NumberValue.of((int) o);
|
||||
@ -394,6 +394,16 @@ public final class java implements Module {
|
||||
return (Value) o;
|
||||
}
|
||||
if (clazz.isArray()) {
|
||||
return arrayToValue(clazz, o);
|
||||
}
|
||||
final Class<?> componentType = clazz.getComponentType();
|
||||
if (componentType != null) {
|
||||
return objectToValue(componentType, o);
|
||||
}
|
||||
return new ObjectValue(o);
|
||||
}
|
||||
|
||||
private static Value arrayToValue(Class<?> clazz, Object o) {
|
||||
final int length = Array.getLength(o);
|
||||
final ArrayValue result = new ArrayValue(length);
|
||||
final Class<?> componentType = clazz.getComponentType();
|
||||
@ -437,12 +447,6 @@ public final class java implements Module {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
final Class<?> componentType = clazz.getComponentType();
|
||||
if (componentType != null) {
|
||||
return objectToValue(componentType, o);
|
||||
}
|
||||
return new ObjectValue(o);
|
||||
}
|
||||
|
||||
private static Object[] valuesToObjects(Value[] args) {
|
||||
Object[] result = new Object[args.length];
|
||||
@ -459,15 +463,8 @@ public final class java implements Module {
|
||||
return value.raw();
|
||||
case Types.STRING:
|
||||
return value.asString();
|
||||
case Types.ARRAY: {
|
||||
final ArrayValue array = (ArrayValue) value;
|
||||
final int size = array.size();
|
||||
final Object[] result = new Object[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
result[i] = valueToObject(array.get(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
case Types.ARRAY:
|
||||
return arrayToObject((ArrayValue) value);
|
||||
}
|
||||
if (value instanceof ObjectValue) {
|
||||
return ((ObjectValue) value).object;
|
||||
@ -477,5 +474,14 @@ public final class java implements Module {
|
||||
}
|
||||
return value.raw();
|
||||
}
|
||||
|
||||
private static Object arrayToObject(ArrayValue value) {
|
||||
final int size = value.size();
|
||||
final Object[] result = new Object[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
result[i] = valueToObject(value.get(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//</editor-fold>
|
||||
}
|
||||
|
@ -430,7 +430,7 @@ public final class jdbc implements Module {
|
||||
set("getBigDecimal", getObjectResult(rs::getBigDecimal, rs::getBigDecimal, (bd) -> new StringValue(bd.toString())));
|
||||
set("getBoolean", getBooleanResult(rs::getBoolean, rs::getBoolean));
|
||||
set("getByte", getNumberResult(rs::getByte, rs::getByte));
|
||||
set("getBytes", getObjectResult(rs::getBytes, rs::getBytes, (bytes) -> ArrayValue.of(bytes)));
|
||||
set("getBytes", getObjectResult(rs::getBytes, rs::getBytes, ArrayValue::of));
|
||||
set("getDate", getObjectResult(rs::getDate, rs::getDate, (date) -> NumberValue.of(date.getTime())));
|
||||
set("getDouble", getNumberResult(rs::getDouble, rs::getDouble));
|
||||
set("getFloat", getNumberResult(rs::getFloat, rs::getFloat));
|
||||
|
@ -8,6 +8,7 @@ import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.IntConsumer;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -83,12 +84,7 @@ public final class robot implements Module {
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface RobotIntConsumer {
|
||||
void accept(int value) throws IllegalArgumentException;
|
||||
}
|
||||
|
||||
private static Function convertFunction(RobotIntConsumer consumer) {
|
||||
private static Function convertFunction(IntConsumer consumer) {
|
||||
return args -> {
|
||||
Arguments.check(1, args.length);
|
||||
try {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.annimon.ownlang.modules.robot;
|
||||
|
||||
import com.annimon.ownlang.Console;
|
||||
import com.annimon.ownlang.lib.Arguments;
|
||||
import com.annimon.ownlang.lib.ArrayValue;
|
||||
import com.annimon.ownlang.lib.Function;
|
||||
@ -10,7 +9,7 @@ import com.annimon.ownlang.lib.Value;
|
||||
|
||||
public final class robot_exec implements Function {
|
||||
|
||||
public static enum Mode { EXEC, EXEC_AND_WAIT };
|
||||
public enum Mode { EXEC, EXEC_AND_WAIT }
|
||||
|
||||
private final Mode mode;
|
||||
|
||||
|
@ -8,7 +8,9 @@ import com.annimon.ownlang.lib.Value;
|
||||
|
||||
public final class NumberFunctions {
|
||||
|
||||
public static Value toHexString(Value... args) {
|
||||
private NumberFunctions() { }
|
||||
|
||||
static Value toHexString(Value... args) {
|
||||
Arguments.check(1, args.length);
|
||||
long value;
|
||||
if (args[0].type() == Types.NUMBER) {
|
||||
|
@ -6,13 +6,15 @@ import com.annimon.ownlang.lib.Value;
|
||||
|
||||
public final class StringFunctions {
|
||||
|
||||
public static Value parseInt(Value... args) {
|
||||
private StringFunctions() { }
|
||||
|
||||
static Value parseInt(Value... args) {
|
||||
Arguments.checkOrOr(1, 2, args.length);
|
||||
final int radix = (args.length == 2) ? args[1].asInt() : 10;
|
||||
return NumberValue.of(Integer.parseInt(args[0].asString(), radix));
|
||||
}
|
||||
|
||||
public static Value parseLong(Value... args) {
|
||||
static Value parseLong(Value... args) {
|
||||
Arguments.checkOrOr(1, 2, args.length);
|
||||
final int radix = (args.length == 2) ? args[1].asInt() : 10;
|
||||
return NumberValue.of(Long.parseLong(args[0].asString(), radix));
|
||||
|
@ -3,7 +3,6 @@ package com.annimon.ownlang.modules.std;
|
||||
import com.annimon.ownlang.lib.Arguments;
|
||||
import com.annimon.ownlang.lib.ArrayValue;
|
||||
import com.annimon.ownlang.lib.Function;
|
||||
import com.annimon.ownlang.lib.StringValue;
|
||||
import com.annimon.ownlang.lib.Value;
|
||||
|
||||
public final class std_split implements Function {
|
||||
|
@ -13,8 +13,7 @@ public final class yaml_decode implements Function {
|
||||
try {
|
||||
final String yamlRaw = args[0].asString();
|
||||
final Object root = new Yaml().load(yamlRaw);
|
||||
final Value process = process(root);
|
||||
return process;
|
||||
return process(root);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Error while parsing yaml", ex);
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ public final class Lexer {
|
||||
|
||||
private static final Map<String, TokenType> KEYWORDS;
|
||||
static {
|
||||
KEYWORDS = new HashMap<String, TokenType>();
|
||||
KEYWORDS = new HashMap<>();
|
||||
KEYWORDS.put("print", TokenType.PRINT);
|
||||
KEYWORDS.put("println", TokenType.PRINTLN);
|
||||
KEYWORDS.put("if", TokenType.IF);
|
||||
|
@ -13,6 +13,8 @@ import com.annimon.ownlang.parser.optimization.SummaryOptimization;
|
||||
|
||||
public final class Optimizer {
|
||||
|
||||
private Optimizer() { }
|
||||
|
||||
public static Statement optimize(Statement statement, int level, boolean showSummary) {
|
||||
if (level == 0) return statement;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import com.annimon.ownlang.lib.StringValue;
|
||||
import com.annimon.ownlang.lib.UserDefinedFunction;
|
||||
import com.annimon.ownlang.parser.ast.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -305,7 +306,7 @@ public final class Parser {
|
||||
}
|
||||
if (lookMatch(0, TokenType.DOT)) {
|
||||
final List<Expression> indices = variableSuffix();
|
||||
if (indices == null || indices.isEmpty()) return expr;
|
||||
if (indices.isEmpty()) return expr;
|
||||
|
||||
if (lookMatch(0, TokenType.LPAREN)) {
|
||||
// next function call
|
||||
@ -441,7 +442,7 @@ public final class Parser {
|
||||
private Expression assignmentStrict() {
|
||||
final int position = pos;
|
||||
final Expression targetExpr = qualifiedName();
|
||||
if ((targetExpr == null) || !(targetExpr instanceof Accessible)) {
|
||||
if (!(targetExpr instanceof Accessible)) {
|
||||
pos = position;
|
||||
return null;
|
||||
}
|
||||
@ -746,7 +747,7 @@ public final class Parser {
|
||||
if (!match(TokenType.WORD)) return null;
|
||||
|
||||
final List<Expression> indices = variableSuffix();
|
||||
if ((indices == null) || indices.isEmpty()) {
|
||||
if (indices.isEmpty()) {
|
||||
return new VariableExpression(current.getText());
|
||||
}
|
||||
return new ContainerAccessExpression(current.getText(), indices);
|
||||
@ -755,7 +756,7 @@ public final class Parser {
|
||||
private List<Expression> variableSuffix() {
|
||||
// .key1.arr1[expr1][expr2].key2
|
||||
if (!lookMatch(0, TokenType.DOT) && !lookMatch(0, TokenType.LBRACKET)) {
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final List<Expression> indices = new ArrayList<>();
|
||||
while (lookMatch(0, TokenType.DOT) || lookMatch(0, TokenType.LBRACKET)) {
|
||||
|
@ -7,6 +7,8 @@ import java.io.InputStream;
|
||||
|
||||
public final class SourceLoader {
|
||||
|
||||
private SourceLoader() { }
|
||||
|
||||
public static String readSource(String name) throws IOException {
|
||||
InputStream is = SourceLoader.class.getResourceAsStream(name);
|
||||
if (is != null) return readAndCloseStream(is);
|
||||
@ -19,9 +21,9 @@ public final class SourceLoader {
|
||||
final ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
final int bufferSize = 1024;
|
||||
final byte[] buffer = new byte[bufferSize];
|
||||
int readed;
|
||||
while ((readed = is.read(buffer)) != -1) {
|
||||
result.write(buffer, 0, readed);
|
||||
int read;
|
||||
while ((read = is.read(buffer)) != -1) {
|
||||
result.write(buffer, 0, read);
|
||||
}
|
||||
is.close();
|
||||
return result.toString("UTF-8");
|
||||
|
@ -16,7 +16,7 @@ import com.annimon.ownlang.lib.Value;
|
||||
*/
|
||||
public final class BinaryExpression implements Expression {
|
||||
|
||||
public static enum Operator {
|
||||
public enum Operator {
|
||||
ADD("+"),
|
||||
SUBTRACT("-"),
|
||||
MULTIPLY("*"),
|
||||
@ -40,7 +40,7 @@ public final class BinaryExpression implements Expression {
|
||||
|
||||
private final String name;
|
||||
|
||||
private Operator(String name) {
|
||||
Operator(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ public final class BinaryExpression implements Expression {
|
||||
}
|
||||
}
|
||||
|
||||
private Value eval(Value value1, Value value2) throws OperationIsNotSupportedException {
|
||||
private Value eval(Value value1, Value value2) {
|
||||
switch (operation) {
|
||||
case ADD: return add(value1, value2);
|
||||
case SUBTRACT: return subtract(value1, value2);
|
||||
@ -141,7 +141,8 @@ public final class BinaryExpression implements Expression {
|
||||
switch (value1.type()) {
|
||||
case Types.NUMBER: return subtract((NumberValue) value1, value2);
|
||||
default:
|
||||
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||
throw new OperationIsNotSupportedException(operation,
|
||||
"for " + Types.typeToString(value1.type()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,17 +178,10 @@ public final class BinaryExpression implements Expression {
|
||||
private Value multiply(Value value1, Value value2) {
|
||||
switch (value1.type()) {
|
||||
case Types.NUMBER: return multiply((NumberValue) value1, value2);
|
||||
case Types.STRING: {
|
||||
final String string1 = value1.asString();
|
||||
final int iterations = value2.asInt();
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
buffer.append(string1);
|
||||
}
|
||||
return new StringValue(buffer.toString());
|
||||
}
|
||||
case Types.STRING: return multiply((StringValue) value1, value2);
|
||||
default:
|
||||
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||
throw new OperationIsNotSupportedException(operation,
|
||||
"for " + Types.typeToString(value1.type()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,11 +214,22 @@ public final class BinaryExpression implements Expression {
|
||||
return NumberValue.of(number1.intValue() * value2.asInt());
|
||||
}
|
||||
|
||||
private Value multiply(StringValue value1, Value value2) {
|
||||
final String string1 = value1.asString();
|
||||
final int iterations = value2.asInt();
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
buffer.append(string1);
|
||||
}
|
||||
return new StringValue(buffer.toString());
|
||||
}
|
||||
|
||||
private Value divide(Value value1, Value value2) {
|
||||
switch (value1.type()) {
|
||||
case Types.NUMBER: return divide((NumberValue) value1, value2);
|
||||
default:
|
||||
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||
throw new OperationIsNotSupportedException(operation,
|
||||
"for " + Types.typeToString(value1.type()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,7 +266,8 @@ public final class BinaryExpression implements Expression {
|
||||
switch (value1.type()) {
|
||||
case Types.NUMBER: return remainder((NumberValue) value1, value2);
|
||||
default:
|
||||
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||
throw new OperationIsNotSupportedException(operation,
|
||||
"for " + Types.typeToString(value1.type()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,7 +304,8 @@ public final class BinaryExpression implements Expression {
|
||||
switch (value1.type()) {
|
||||
case Types.ARRAY: return ArrayValue.add((ArrayValue) value1, value2);
|
||||
default:
|
||||
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||
throw new OperationIsNotSupportedException(operation,
|
||||
"for " + Types.typeToString(value1.type()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -306,7 +313,8 @@ public final class BinaryExpression implements Expression {
|
||||
switch (value1.type()) {
|
||||
case Types.NUMBER: return and((NumberValue) value1, value2);
|
||||
default:
|
||||
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||
throw new OperationIsNotSupportedException(operation,
|
||||
"for " + Types.typeToString(value1.type()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,7 +339,8 @@ public final class BinaryExpression implements Expression {
|
||||
switch (value1.type()) {
|
||||
case Types.NUMBER: return or((NumberValue) value1, value2);
|
||||
default:
|
||||
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||
throw new OperationIsNotSupportedException(operation,
|
||||
"for " + Types.typeToString(value1.type()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,7 +365,8 @@ public final class BinaryExpression implements Expression {
|
||||
switch (value1.type()) {
|
||||
case Types.NUMBER: return xor((NumberValue) value1, value2);
|
||||
default:
|
||||
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||
throw new OperationIsNotSupportedException(operation,
|
||||
"for " + Types.typeToString(value1.type()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -380,13 +390,10 @@ public final class BinaryExpression implements Expression {
|
||||
private Value lshift(Value value1, Value value2) {
|
||||
switch (value1.type()) {
|
||||
case Types.NUMBER: return lshift((NumberValue) value1, value2);
|
||||
case Types.ARRAY: {
|
||||
if (value2.type() != Types.ARRAY)
|
||||
throw new TypeException("Cannot merge non array value to array");
|
||||
return ArrayValue.merge((ArrayValue) value1, (ArrayValue) value2);
|
||||
}
|
||||
case Types.ARRAY: return lshift((ArrayValue) value1, value2);
|
||||
default:
|
||||
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||
throw new OperationIsNotSupportedException(operation,
|
||||
"for " + Types.typeToString(value1.type()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -407,11 +414,18 @@ public final class BinaryExpression implements Expression {
|
||||
return NumberValue.of(number1.intValue() << value2.asInt());
|
||||
}
|
||||
|
||||
private Value lshift(ArrayValue value1, Value value2) {
|
||||
if (value2.type() != Types.ARRAY)
|
||||
throw new TypeException("Cannot merge non array value to array");
|
||||
return ArrayValue.merge(value1, (ArrayValue) value2);
|
||||
}
|
||||
|
||||
private Value rshift(Value value1, Value value2) {
|
||||
switch (value1.type()) {
|
||||
case Types.NUMBER: return rshift((NumberValue) value1, value2);
|
||||
default:
|
||||
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||
throw new OperationIsNotSupportedException(operation,
|
||||
"for " + Types.typeToString(value1.type()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,7 +450,8 @@ public final class BinaryExpression implements Expression {
|
||||
switch (value1.type()) {
|
||||
case Types.NUMBER: return urshift((NumberValue) value1, value2);
|
||||
default:
|
||||
throw new OperationIsNotSupportedException(operation, "for " + Types.typeToString(value1.type()));
|
||||
throw new OperationIsNotSupportedException(operation,
|
||||
"for " + Types.typeToString(value1.type()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ import com.annimon.ownlang.lib.Value;
|
||||
*/
|
||||
public final class ConditionalExpression implements Expression {
|
||||
|
||||
public static enum Operator {
|
||||
public enum Operator {
|
||||
EQUALS("=="),
|
||||
NOT_EQUALS("!="),
|
||||
|
||||
|
@ -205,7 +205,7 @@ public final class MatchExpression extends InterruptableNode implements Expressi
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static abstract class Pattern {
|
||||
public abstract static class Pattern {
|
||||
public Statement result;
|
||||
public Expression optCondition;
|
||||
|
||||
|
@ -12,7 +12,7 @@ import com.annimon.ownlang.lib.Value;
|
||||
*/
|
||||
public final class UnaryExpression implements Expression, Statement {
|
||||
|
||||
public static enum Operator {
|
||||
public enum Operator {
|
||||
INCREMENT_PREFIX("++"),
|
||||
DECREMENT_PREFIX("--"),
|
||||
INCREMENT_POSTFIX("++"),
|
||||
|
@ -260,8 +260,7 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
|
||||
final String variable = ((MatchExpression.VariablePattern) pattern).variable;
|
||||
final VariableExpression expr = new VariableExpression(variable);
|
||||
final Node node = expr.accept(this, t);
|
||||
if (node != expr) {
|
||||
if (isValue(node)) {
|
||||
if ((node != expr) && isValue(node)) {
|
||||
changed = true;
|
||||
final Value value = ((ValueExpression) node).value;
|
||||
final Expression optCondition = pattern.optCondition;
|
||||
@ -271,7 +270,6 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
|
||||
pattern.result = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pattern instanceof MatchExpression.TuplePattern) {
|
||||
final MatchExpression.TuplePattern tuple = (MatchExpression.TuplePattern) pattern;
|
||||
|
@ -34,7 +34,7 @@ public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder>
|
||||
|
||||
@Override
|
||||
public StringBuilder visit(AssignmentExpression s, StringBuilder t) {
|
||||
((Node) s.target).accept(this, t);
|
||||
s.target.accept(this, t);
|
||||
t.append(' ').append((s.operation == null) ? "" : s.operation);
|
||||
t.append("= ");
|
||||
s.expression.accept(this, t);
|
||||
@ -203,7 +203,8 @@ public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder>
|
||||
|
||||
@Override
|
||||
public StringBuilder visit(FunctionalExpression s, StringBuilder t) {
|
||||
if (s.functionExpr instanceof ValueExpression && ((ValueExpression)s.functionExpr).value.type() == Types.STRING) {
|
||||
if (s.functionExpr instanceof ValueExpression
|
||||
&& ((ValueExpression)s.functionExpr).value.type() == Types.STRING) {
|
||||
t.append(((ValueExpression)s.functionExpr).value.asString());
|
||||
} else {
|
||||
s.functionExpr.accept(this, t);
|
||||
|
@ -17,6 +17,8 @@ import java.util.Set;
|
||||
|
||||
public final class VisitorUtils {
|
||||
|
||||
private VisitorUtils() { }
|
||||
|
||||
public static boolean isValue(Node node) {
|
||||
return (node instanceof ValueExpression);
|
||||
}
|
||||
|
@ -7,19 +7,10 @@ import com.annimon.ownlang.lib.Value;
|
||||
import com.annimon.ownlang.lib.Variables;
|
||||
import com.annimon.ownlang.modules.Module;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
@ -28,14 +19,17 @@ public final class ModulesInfoCreator {
|
||||
|
||||
private static final String MODULES_PATH = "src/main/java/com/annimon/ownlang/modules";
|
||||
|
||||
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
public static void main(String[] args)
|
||||
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
|
||||
final Class<Module> clazz = Module.class; // get classloader for package
|
||||
|
||||
final List<ModuleInfo> moduleInfos = new ArrayList<>();
|
||||
|
||||
String[] moduleNames = Arrays.stream(new File(MODULES_PATH).listFiles())
|
||||
.filter(p -> p.isDirectory())
|
||||
.map(p -> p.getName())
|
||||
String[] moduleNames = Optional.ofNullable(new File(MODULES_PATH).listFiles())
|
||||
.map(Arrays::stream)
|
||||
.orElse(Stream.empty())
|
||||
.filter(File::isDirectory)
|
||||
.map(File::getName)
|
||||
.toArray(String[]::new);
|
||||
for (String moduleName : moduleNames) {
|
||||
final String moduleClassPath = String.format("com.annimon.ownlang.modules.%s.%s", moduleName, moduleName);
|
||||
@ -57,16 +51,16 @@ public final class ModulesInfoCreator {
|
||||
|
||||
System.out.println("Total modules: " + moduleInfos.size());
|
||||
System.out.println("Total functions: " + moduleInfos.stream()
|
||||
.flatMap(m -> m.functions.stream())
|
||||
.count()
|
||||
.mapToLong(m -> m.functions.size())
|
||||
.sum()
|
||||
);
|
||||
System.out.println("Total constants: " + moduleInfos.stream()
|
||||
.flatMap(m -> m.constants.keySet().stream())
|
||||
.count()
|
||||
.mapToLong(m -> m.constants.keySet().size())
|
||||
.sum()
|
||||
);
|
||||
}
|
||||
|
||||
private static void printAsJson(List<ModuleInfo> moduleInfos) throws JSONException {
|
||||
private static void printAsJson(List<ModuleInfo> moduleInfos) {
|
||||
final JSONArray modulesJson = new JSONArray();
|
||||
for (ModuleInfo moduleInfo : moduleInfos) {
|
||||
modulesJson.put(new JSONObject(moduleInfo.info()));
|
||||
@ -128,7 +122,7 @@ public final class ModulesInfoCreator {
|
||||
public List<Map<String, Object>> constants() {
|
||||
final List<Map<String, Object>> result = new ArrayList<>();
|
||||
constants.entrySet().stream()
|
||||
.sorted(Comparator.comparing(e -> e.getKey()))
|
||||
.sorted(Comparator.comparing(Map.Entry::getKey))
|
||||
.forEach(entry -> {
|
||||
final Value value = entry.getValue();
|
||||
|
||||
@ -140,7 +134,7 @@ public final class ModulesInfoCreator {
|
||||
String text = ((Map<Value, Value>) value.raw()).entrySet().stream()
|
||||
.sorted(Comparator.comparing(
|
||||
e -> ((MapValue)value).size() > 16 ? e.getKey() : e.getValue()))
|
||||
.map(s -> s.toString())
|
||||
.map(Object::toString)
|
||||
.collect(Collectors.joining(", ", "{", "}"));
|
||||
constant.put("value", text);
|
||||
} else {
|
||||
|
@ -68,7 +68,6 @@ public final class OptimizationDumper {
|
||||
}
|
||||
|
||||
private static String nodeToString(Node n) {
|
||||
// return n.toString();
|
||||
return n.accept(new PrintVisitor(), new StringBuilder()).toString();
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,8 @@ public final class Repl {
|
||||
|
||||
int maxLength = commands.stream()
|
||||
.mapToInt(String::length)
|
||||
.max().getAsInt();
|
||||
.max()
|
||||
.orElse(20);
|
||||
|
||||
final int maxCols = 2;
|
||||
final int size = commands.size();
|
||||
|
@ -2,6 +2,7 @@ package com.annimon.ownlang.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
import org.openjdk.jmh.runner.Runner;
|
||||
@ -31,7 +32,8 @@ public class LexerBenchmarkTest {
|
||||
}
|
||||
}
|
||||
|
||||
//@Test
|
||||
@Ignore
|
||||
@Test
|
||||
public void executeBenchmark() throws RunnerException {
|
||||
Options opt = new OptionsBuilder()
|
||||
.include(LexerBenchmarkTest.class.getSimpleName())
|
||||
|
@ -3,6 +3,7 @@ package com.annimon.ownlang.parser;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
@ -33,7 +34,8 @@ public class ParserBenchmarkTest {
|
||||
}
|
||||
}
|
||||
|
||||
//@Test
|
||||
@Ignore
|
||||
@Test
|
||||
public void executeBenchmark() throws RunnerException {
|
||||
Options opt = new OptionsBuilder()
|
||||
.include(ParserBenchmarkTest.class.getSimpleName())
|
||||
|
Loading…
Reference in New Issue
Block a user