Значительные исправления

This commit is contained in:
Victor 2018-10-19 19:45:30 +03:00
parent be9bdb0311
commit c7dd50c9ad
40 changed files with 249 additions and 192 deletions

View File

@ -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')}";
}
"""

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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));

View File

@ -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();

View File

@ -15,6 +15,8 @@ public final class Functions {
functions = new HashMap<>();
}
private Functions() { }
public static void clear() {
functions.clear();
}

View File

@ -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];

View File

@ -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() { }
}

View File

@ -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)

View File

@ -35,6 +35,8 @@ public final class Variables {
Variables.clear();
}
private Variables() { }
public static Map<String, Value> variables() {
return scope.variables;
}

View File

@ -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),

View File

@ -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));
}

View File

@ -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));

View File

@ -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) {

View File

@ -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);

View File

@ -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();

View File

@ -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,48 +394,7 @@ public final class java implements Module {
return (Value) o;
}
if (clazz.isArray()) {
final int length = Array.getLength(o);
final ArrayValue result = new ArrayValue(length);
final Class<?> componentType = clazz.getComponentType();
int i = 0;
if (boolean.class.isAssignableFrom(componentType)) {
for (boolean element : (boolean[]) o) {
result.set(i++, NumberValue.fromBoolean(element));
}
} else if (byte.class.isAssignableFrom(componentType)) {
for (byte element : (byte[]) o) {
result.set(i++, NumberValue.of(element));
}
} else if (char.class.isAssignableFrom(componentType)) {
for (char element : (char[]) o) {
result.set(i++, NumberValue.of(element));
}
} else if (double.class.isAssignableFrom(componentType)) {
for (double element : (double[]) o) {
result.set(i++, NumberValue.of(element));
}
} else if (float.class.isAssignableFrom(componentType)) {
for (float element : (float[]) o) {
result.set(i++, NumberValue.of(element));
}
} else if (int.class.isAssignableFrom(componentType)) {
for (int element : (int[]) o) {
result.set(i++, NumberValue.of(element));
}
} else if (long.class.isAssignableFrom(componentType)) {
for (long element : (long[]) o) {
result.set(i++, NumberValue.of(element));
}
} else if (short.class.isAssignableFrom(componentType)) {
for (short element : (short[]) o) {
result.set(i++, NumberValue.of(element));
}
} else {
for (Object element : (Object[]) o) {
result.set(i++, objectToValue(element));
}
}
return result;
return arrayToValue(clazz, o);
}
final Class<?> componentType = clazz.getComponentType();
if (componentType != null) {
@ -444,6 +403,51 @@ public final class java implements Module {
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();
int i = 0;
if (boolean.class.isAssignableFrom(componentType)) {
for (boolean element : (boolean[]) o) {
result.set(i++, NumberValue.fromBoolean(element));
}
} else if (byte.class.isAssignableFrom(componentType)) {
for (byte element : (byte[]) o) {
result.set(i++, NumberValue.of(element));
}
} else if (char.class.isAssignableFrom(componentType)) {
for (char element : (char[]) o) {
result.set(i++, NumberValue.of(element));
}
} else if (double.class.isAssignableFrom(componentType)) {
for (double element : (double[]) o) {
result.set(i++, NumberValue.of(element));
}
} else if (float.class.isAssignableFrom(componentType)) {
for (float element : (float[]) o) {
result.set(i++, NumberValue.of(element));
}
} else if (int.class.isAssignableFrom(componentType)) {
for (int element : (int[]) o) {
result.set(i++, NumberValue.of(element));
}
} else if (long.class.isAssignableFrom(componentType)) {
for (long element : (long[]) o) {
result.set(i++, NumberValue.of(element));
}
} else if (short.class.isAssignableFrom(componentType)) {
for (short element : (short[]) o) {
result.set(i++, NumberValue.of(element));
}
} else {
for (Object element : (Object[]) o) {
result.set(i++, objectToValue(element));
}
}
return result;
}
private static Object[] valuesToObjects(Value[] args) {
Object[] result = new Object[args.length];
for (int i = 0; i < args.length; i++) {
@ -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>
}

View File

@ -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));

View File

@ -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 {

View File

@ -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;

View File

@ -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) {

View File

@ -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));

View File

@ -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 {

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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)) {

View File

@ -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");

View File

@ -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()));
}
}
@ -219,12 +213,23 @@ 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,16 +390,13 @@ 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()));
}
}
private Value lshift(NumberValue value1, Value value2) {
final Number number1 = value1.raw();
if (value2.type() == Types.NUMBER) {
@ -406,12 +413,19 @@ 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()));
}
}

View File

@ -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("!="),

View File

@ -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;

View File

@ -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("++"),

View File

@ -260,16 +260,14 @@ 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)) {
changed = true;
final Value value = ((ValueExpression) node).value;
final Expression optCondition = pattern.optCondition;
final Statement result = pattern.result;
pattern = new MatchExpression.ConstantPattern(value);
pattern.optCondition = optCondition;
pattern.result = result;
}
if ((node != expr) && isValue(node)) {
changed = true;
final Value value = ((ValueExpression) node).value;
final Expression optCondition = pattern.optCondition;
final Statement result = pattern.result;
pattern = new MatchExpression.ConstantPattern(value);
pattern.optCondition = optCondition;
pattern.result = result;
}
}

View File

@ -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);

View File

@ -17,6 +17,8 @@ import java.util.Set;
public final class VisitorUtils {
private VisitorUtils() { }
public static boolean isValue(Node node) {
return (node instanceof ValueExpression);
}

View File

@ -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 {

View File

@ -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();
}

View File

@ -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();

View File

@ -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())

View File

@ -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())