From c7f87f75f6068f19ec7ea797d45575ef38e386b8 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 10 Nov 2017 11:13:46 +0200 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D1=91?= =?UTF-8?q?=D0=BD=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/canvas/animate_line.own | 2 +- examples/canvas/fx_koch_snowflake.own | 70 +++++++++++++++++++ .../com/annimon/ownlang/lib/ValueUtils.java | 10 +++ .../ownlang/modules/forms/ComponentValue.java | 16 ++--- .../ownlang/modules/forms/JButtonValue.java | 9 +-- .../modules/forms/JTextFieldValue.java | 9 +-- .../functional/functional_flatmap.java | 8 +-- .../functional/functional_foreach.java | 14 ++-- .../modules/functional/functional_sortby.java | 8 +-- .../annimon/ownlang/modules/robot/robot.java | 59 ++++++++-------- .../annimon/ownlang/modules/std/std_sort.java | 7 +- .../ownlang/parser/LexerBenchmarkTest.java | 4 +- .../ownlang/parser/ParserBenchmarkTest.java | 4 +- 13 files changed, 140 insertions(+), 80 deletions(-) create mode 100644 examples/canvas/fx_koch_snowflake.own diff --git a/examples/canvas/animate_line.own b/examples/canvas/animate_line.own index d5edc19..758d5b6 100644 --- a/examples/canvas/animate_line.own +++ b/examples/canvas/animate_line.own @@ -53,4 +53,4 @@ def sethsbcolor(h1) { case 4: color(f*255, 0, 255) case 5: color(255, 0, 255-f*255) } -} \ No newline at end of file +} diff --git a/examples/canvas/fx_koch_snowflake.own b/examples/canvas/fx_koch_snowflake.own new file mode 100644 index 0000000..7e96b6b --- /dev/null +++ b/examples/canvas/fx_koch_snowflake.own @@ -0,0 +1,70 @@ +use "canvasfx" +use "math" +use "functional" + +// https://github.com/SeTSeR/KochSnowflake + +width = 675 height = 500 +context = window("Koch Snowflake", width, height) + +GO = 0 TURN = 1 + +def Fractal(startStep = 0) { + result = {} + result.fract = startStep ? [[GO, startStep]] : [] + result.next = def(fract) { + fractal = Fractal() + def translate(input) = input[0] == GO ? [input[0], input[1] / 3] : input + fractlist = map(fract, ::translate) + fractal.fract = fractlist + fractal.fract ::= [TURN, -PI / 3] + fractal.fract <<= fractlist + fractal.fract ::= [TURN, 2*PI / 3] + fractal.fract <<= fractlist + fractal.fract ::= [TURN, -PI / 3] + fractal.fract <<= fractlist + return fractal + } + result.toDraw = def(fract) { + res = Fractal() + res.fract = fract + res.fract ::= [TURN, 2*PI / 3] + res.fract <<= fract + res.fract ::= [TURN, 2*PI / 3] + res.fract <<= fract + return res + } + return result +} + +def draw(fractal) { + x = 200 + y = height - 100 / sqrt(3) + angle = -PI / 2 + context.setFill(Color.BLACK) + context.fillRect(0, 0, width, height) + context.setStroke(Color.GREEN) + context.beginPath() + context.moveTo(x, y) + for action : fractal.fract { + match action[0] { + case GO: { + x += action[1] * cos(angle) + y += action[1] * sin(angle) + context.lineTo(x, y) + } + case TURN: angle += action[1] + } + } + context.closePath() + context.stroke() +} + +fractal = Fractal(400.0) +draw(fractal.toDraw(fractal.fract)) +addEventHandler(Events.KEY_PRESSED, def(e) { + if (e.code == KeyCode.SPACE) { + fractal = fractal.next(fractal.fract) + draw(fractal.toDraw(fractal.fract)) + } +}) \ No newline at end of file diff --git a/src/main/java/com/annimon/ownlang/lib/ValueUtils.java b/src/main/java/com/annimon/ownlang/lib/ValueUtils.java index 57aba13..c11bbfb 100644 --- a/src/main/java/com/annimon/ownlang/lib/ValueUtils.java +++ b/src/main/java/com/annimon/ownlang/lib/ValueUtils.java @@ -1,5 +1,6 @@ package com.annimon.ownlang.lib; +import com.annimon.ownlang.exceptions.TypeException; import java.util.Iterator; import java.util.Map; import org.json.JSONArray; @@ -99,4 +100,13 @@ public final class ValueUtils { } return result; } + + public static Function consumeFunction(Value value, int argumentNumber) throws TypeException { + final int type = value.type(); + if (type != Types.FUNCTION) { + throw new TypeException("Function expected at argument " + (argumentNumber + 1) + + ", but found " + Types.typeToString(type)); + } + return ((FunctionValue) value).getValue(); + } } diff --git a/src/main/java/com/annimon/ownlang/modules/forms/ComponentValue.java b/src/main/java/com/annimon/ownlang/modules/forms/ComponentValue.java index 5ab56f8..15a0de2 100644 --- a/src/main/java/com/annimon/ownlang/modules/forms/ComponentValue.java +++ b/src/main/java/com/annimon/ownlang/modules/forms/ComponentValue.java @@ -1,16 +1,14 @@ package com.annimon.ownlang.modules.forms; -import com.annimon.ownlang.exceptions.TypeException; import com.annimon.ownlang.lib.Arguments; import com.annimon.ownlang.lib.ArrayValue; -import static com.annimon.ownlang.lib.Converters.*; import com.annimon.ownlang.lib.Function; import com.annimon.ownlang.lib.FunctionValue; import com.annimon.ownlang.lib.MapValue; import com.annimon.ownlang.lib.NumberValue; import com.annimon.ownlang.lib.StringValue; -import com.annimon.ownlang.lib.Types; import com.annimon.ownlang.lib.Value; +import com.annimon.ownlang.lib.ValueUtils; import java.awt.Component; import java.awt.Dimension; import java.awt.Point; @@ -18,6 +16,12 @@ import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.function.Consumer; import java.util.function.Supplier; +import static com.annimon.ownlang.lib.Converters.booleanOptToVoid; +import static com.annimon.ownlang.lib.Converters.stringToVoid; +import static com.annimon.ownlang.lib.Converters.voidToBoolean; +import static com.annimon.ownlang.lib.Converters.voidToInt; +import static com.annimon.ownlang.lib.Converters.voidToString; +import static com.annimon.ownlang.lib.Converters.voidToVoid; public abstract class ComponentValue extends MapValue { @@ -75,11 +79,7 @@ public abstract class ComponentValue extends MapValue { private Value addKeyListener(Value... args) { Arguments.check(1, args.length); - final int type = args[0].type(); - if (type != Types.FUNCTION) { - throw new TypeException("Function expected, but found " + Types.typeToString(type)); - } - final Function action = ((FunctionValue) args[0]).getValue(); + final Function action = ValueUtils.consumeFunction(args[0], 0); component.addKeyListener(new KeyListener() { @Override diff --git a/src/main/java/com/annimon/ownlang/modules/forms/JButtonValue.java b/src/main/java/com/annimon/ownlang/modules/forms/JButtonValue.java index 5afce2f..87766fb 100644 --- a/src/main/java/com/annimon/ownlang/modules/forms/JButtonValue.java +++ b/src/main/java/com/annimon/ownlang/modules/forms/JButtonValue.java @@ -1,12 +1,11 @@ package com.annimon.ownlang.modules.forms; -import com.annimon.ownlang.exceptions.TypeException; import com.annimon.ownlang.lib.Arguments; import com.annimon.ownlang.lib.Function; import com.annimon.ownlang.lib.FunctionValue; import com.annimon.ownlang.lib.NumberValue; -import com.annimon.ownlang.lib.Types; import com.annimon.ownlang.lib.Value; +import com.annimon.ownlang.lib.ValueUtils; import javax.swing.JButton; public class JButtonValue extends JComponentValue { @@ -26,11 +25,7 @@ public class JButtonValue extends JComponentValue { private Value addActionListener(Value... args) { Arguments.check(1, args.length); - final int type = args[0].type(); - if (type != Types.FUNCTION) { - throw new TypeException("Function expected, but found " + Types.typeToString(type)); - } - final Function action = ((FunctionValue) args[0]).getValue(); + final Function action = ValueUtils.consumeFunction(args[0], 0); button.addActionListener(e -> action.execute()); return NumberValue.ZERO; } diff --git a/src/main/java/com/annimon/ownlang/modules/forms/JTextFieldValue.java b/src/main/java/com/annimon/ownlang/modules/forms/JTextFieldValue.java index d6fed17..841b92a 100644 --- a/src/main/java/com/annimon/ownlang/modules/forms/JTextFieldValue.java +++ b/src/main/java/com/annimon/ownlang/modules/forms/JTextFieldValue.java @@ -1,14 +1,13 @@ package com.annimon.ownlang.modules.forms; -import com.annimon.ownlang.exceptions.TypeException; import com.annimon.ownlang.lib.Arguments; import static com.annimon.ownlang.lib.Converters.*; import com.annimon.ownlang.lib.Function; import com.annimon.ownlang.lib.FunctionValue; import com.annimon.ownlang.lib.NumberValue; -import com.annimon.ownlang.lib.Types; import com.annimon.ownlang.lib.Value; import javax.swing.JTextField; +import static com.annimon.ownlang.lib.ValueUtils.consumeFunction; public class JTextFieldValue extends JComponentValue { @@ -41,11 +40,7 @@ public class JTextFieldValue extends JComponentValue { private Value addActionListener(Value... args) { Arguments.check(1, args.length); - final int type = args[0].type(); - if (type != Types.FUNCTION) { - throw new TypeException("Function expected, but found " + Types.typeToString(type)); - } - final Function action = ((FunctionValue) args[0]).getValue(); + Function action = consumeFunction(args[0], 1); textField.addActionListener(e -> action.execute()); return NumberValue.ZERO; } diff --git a/src/main/java/com/annimon/ownlang/modules/functional/functional_flatmap.java b/src/main/java/com/annimon/ownlang/modules/functional/functional_flatmap.java index 5130810..333e133 100644 --- a/src/main/java/com/annimon/ownlang/modules/functional/functional_flatmap.java +++ b/src/main/java/com/annimon/ownlang/modules/functional/functional_flatmap.java @@ -4,9 +4,9 @@ import com.annimon.ownlang.exceptions.TypeException; import com.annimon.ownlang.lib.Arguments; import com.annimon.ownlang.lib.ArrayValue; import com.annimon.ownlang.lib.Function; -import com.annimon.ownlang.lib.FunctionValue; import com.annimon.ownlang.lib.Types; import com.annimon.ownlang.lib.Value; +import com.annimon.ownlang.lib.ValueUtils; import java.util.ArrayList; import java.util.List; @@ -18,11 +18,7 @@ public final class functional_flatmap implements Function { if (args[0].type() != Types.ARRAY) { throw new TypeException("Array expected in first argument"); } - if (args[1].type() != Types.FUNCTION) { - throw new TypeException("Function expected in second argument"); - } - - final Function mapper = ((FunctionValue) args[1]).getValue(); + final Function mapper = ValueUtils.consumeFunction(args[1], 1); return flatMapArray((ArrayValue) args[0], mapper); } diff --git a/src/main/java/com/annimon/ownlang/modules/functional/functional_foreach.java b/src/main/java/com/annimon/ownlang/modules/functional/functional_foreach.java index 239e3f3..fc5117e 100644 --- a/src/main/java/com/annimon/ownlang/modules/functional/functional_foreach.java +++ b/src/main/java/com/annimon/ownlang/modules/functional/functional_foreach.java @@ -1,7 +1,13 @@ package com.annimon.ownlang.modules.functional; import com.annimon.ownlang.exceptions.TypeException; -import com.annimon.ownlang.lib.*; +import com.annimon.ownlang.lib.Arguments; +import com.annimon.ownlang.lib.ArrayValue; +import com.annimon.ownlang.lib.Function; +import com.annimon.ownlang.lib.MapValue; +import com.annimon.ownlang.lib.Types; +import com.annimon.ownlang.lib.Value; +import com.annimon.ownlang.lib.ValueUtils; import java.util.Map; public final class functional_foreach implements Function { @@ -9,12 +15,8 @@ public final class functional_foreach implements Function { @Override public Value execute(Value... args) { Arguments.check(2, args.length); - - if (args[1].type() != Types.FUNCTION) { - throw new TypeException("Function expected in second arg"); - } final Value container = args[0]; - final Function consumer = ((FunctionValue) args[1]).getValue(); + final Function consumer = ValueUtils.consumeFunction(args[1], 1); if (container.type() == Types.ARRAY) { final ArrayValue array = (ArrayValue) container; for (Value element : array) { diff --git a/src/main/java/com/annimon/ownlang/modules/functional/functional_sortby.java b/src/main/java/com/annimon/ownlang/modules/functional/functional_sortby.java index 926047d..5e87598 100644 --- a/src/main/java/com/annimon/ownlang/modules/functional/functional_sortby.java +++ b/src/main/java/com/annimon/ownlang/modules/functional/functional_sortby.java @@ -4,9 +4,9 @@ import com.annimon.ownlang.exceptions.TypeException; import com.annimon.ownlang.lib.Arguments; import com.annimon.ownlang.lib.ArrayValue; import com.annimon.ownlang.lib.Function; -import com.annimon.ownlang.lib.FunctionValue; import com.annimon.ownlang.lib.Types; import com.annimon.ownlang.lib.Value; +import com.annimon.ownlang.lib.ValueUtils; import java.util.Arrays; public final class functional_sortby implements Function { @@ -17,12 +17,8 @@ public final class functional_sortby implements Function { if (args[0].type() != Types.ARRAY) { throw new TypeException("Array expected in first argument"); } - if (args[1].type() != Types.FUNCTION) { - throw new TypeException("Function expected in second argument"); - } - final Value[] elements = ((ArrayValue) args[0]).getCopyElements(); - final Function function = ((FunctionValue) args[1]).getValue(); + final Function function = ValueUtils.consumeFunction(args[1], 1); Arrays.sort(elements, (o1, o2) -> function.execute(o1).compareTo(function.execute(o2))); return new ArrayValue(elements); } diff --git a/src/main/java/com/annimon/ownlang/modules/robot/robot.java b/src/main/java/com/annimon/ownlang/modules/robot/robot.java index 090838e..0d3fa8e 100644 --- a/src/main/java/com/annimon/ownlang/modules/robot/robot.java +++ b/src/main/java/com/annimon/ownlang/modules/robot/robot.java @@ -42,41 +42,44 @@ public final class robot implements Module { @Override public void init() { initConstants(); - initialize(); - - Functions.set("click", convertFunction(robot::click)); - Functions.set("delay", convertFunction(awtRobot::delay)); - Functions.set("setAutoDelay", convertFunction(awtRobot::setAutoDelay)); - Functions.set("keyPress", convertFunction(awtRobot::keyPress)); - Functions.set("keyRelease", convertFunction(awtRobot::keyRelease)); - Functions.set("mousePress", convertFunction(awtRobot::mousePress)); - Functions.set("mouseRelease", convertFunction(awtRobot::mouseRelease)); - Functions.set("mouseWheel", convertFunction(awtRobot::mouseWheel)); - Functions.set("mouseMove", (args) -> { - Arguments.check(2, args.length); - try { - awtRobot.mouseMove(args[0].asInt(), args[1].asInt()); - } catch (IllegalArgumentException iae) { } - return NumberValue.ZERO; - }); - Functions.set("typeText", (args) -> { - Arguments.check(1, args.length); - try { - typeText(args[0].asString()); - } catch (IllegalArgumentException iae) { } - return NumberValue.ZERO; - }); - Functions.set("toClipboard", new robot_toclipboard()); - Functions.set("fromClipboard", new robot_fromclipboard()); + boolean isRobotInitialized = initialize(); + if (isRobotInitialized) { + Functions.set("click", convertFunction(robot::click)); + Functions.set("delay", convertFunction(awtRobot::delay)); + Functions.set("setAutoDelay", convertFunction(awtRobot::setAutoDelay)); + Functions.set("keyPress", convertFunction(awtRobot::keyPress)); + Functions.set("keyRelease", convertFunction(awtRobot::keyRelease)); + Functions.set("mousePress", convertFunction(awtRobot::mousePress)); + Functions.set("mouseRelease", convertFunction(awtRobot::mouseRelease)); + Functions.set("mouseWheel", convertFunction(awtRobot::mouseWheel)); + Functions.set("mouseMove", (args) -> { + Arguments.check(2, args.length); + try { + awtRobot.mouseMove(args[0].asInt(), args[1].asInt()); + } catch (IllegalArgumentException iae) { } + return NumberValue.ZERO; + }); + Functions.set("typeText", (args) -> { + Arguments.check(1, args.length); + try { + typeText(args[0].asString()); + } catch (IllegalArgumentException iae) { } + return NumberValue.ZERO; + }); + Functions.set("toClipboard", new robot_toclipboard()); + Functions.set("fromClipboard", new robot_fromclipboard()); + } Functions.set("execProcess", new robot_exec(robot_exec.Mode.EXEC)); Functions.set("execProcessAndWait", new robot_exec(robot_exec.Mode.EXEC_AND_WAIT)); } - private static void initialize() { + private static boolean initialize() { try { awtRobot = new Robot(); + return true; } catch (AWTException awte) { - throw new RuntimeException("Unable to create robot instance", awte); + //throw new RuntimeException("Unable to create robot instance", awte); + return false; } } diff --git a/src/main/java/com/annimon/ownlang/modules/std/std_sort.java b/src/main/java/com/annimon/ownlang/modules/std/std_sort.java index 4dc39b8..22608b4 100644 --- a/src/main/java/com/annimon/ownlang/modules/std/std_sort.java +++ b/src/main/java/com/annimon/ownlang/modules/std/std_sort.java @@ -5,9 +5,9 @@ import com.annimon.ownlang.exceptions.TypeException; import com.annimon.ownlang.lib.Arguments; import com.annimon.ownlang.lib.ArrayValue; import com.annimon.ownlang.lib.Function; -import com.annimon.ownlang.lib.FunctionValue; import com.annimon.ownlang.lib.Types; import com.annimon.ownlang.lib.Value; +import com.annimon.ownlang.lib.ValueUtils; import java.util.Arrays; public final class std_sort implements Function { @@ -25,10 +25,7 @@ public final class std_sort implements Function { Arrays.sort(elements); break; case 2: - if (args[1].type() != Types.FUNCTION) { - throw new TypeException("Function expected in second argument"); - } - final Function comparator = ((FunctionValue) args[1]).getValue(); + final Function comparator = ValueUtils.consumeFunction(args[1], 1); Arrays.sort(elements, (o1, o2) -> comparator.execute(o1, o2).asInt()); break; default: diff --git a/src/test/java/com/annimon/ownlang/parser/LexerBenchmarkTest.java b/src/test/java/com/annimon/ownlang/parser/LexerBenchmarkTest.java index 934b0fa..13930e0 100644 --- a/src/test/java/com/annimon/ownlang/parser/LexerBenchmarkTest.java +++ b/src/test/java/com/annimon/ownlang/parser/LexerBenchmarkTest.java @@ -2,7 +2,6 @@ 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; @@ -13,7 +12,6 @@ import org.openjdk.jmh.runner.options.OptionsBuilder; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @State(Scope.Benchmark) -@Ignore public class LexerBenchmarkTest { @Param({"1000"}) @@ -33,7 +31,7 @@ public class LexerBenchmarkTest { } } - @Test + //@Test public void executeBenchmark() throws RunnerException { Options opt = new OptionsBuilder() .include(LexerBenchmarkTest.class.getSimpleName()) diff --git a/src/test/java/com/annimon/ownlang/parser/ParserBenchmarkTest.java b/src/test/java/com/annimon/ownlang/parser/ParserBenchmarkTest.java index f359564..fe2528f 100644 --- a/src/test/java/com/annimon/ownlang/parser/ParserBenchmarkTest.java +++ b/src/test/java/com/annimon/ownlang/parser/ParserBenchmarkTest.java @@ -3,7 +3,6 @@ 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; @@ -15,7 +14,6 @@ import org.openjdk.jmh.runner.options.OptionsBuilder; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @State(Scope.Benchmark) -@Ignore public class ParserBenchmarkTest { @Param({"1000"}) @@ -35,7 +33,7 @@ public class ParserBenchmarkTest { } } - @Test + //@Test public void executeBenchmark() throws RunnerException { Options opt = new OptionsBuilder() .include(ParserBenchmarkTest.class.getSimpleName())