diff --git a/program.own b/program.own index 274fb6a..d49a542 100644 --- a/program.own +++ b/program.own @@ -240,4 +240,6 @@ println `extended word variable` def `::`(v1, v2) = string(v1) + string(v2) println 1 :: 2 :: 3 -println "\u042a" \ No newline at end of file +println "\u042a" + +include "visitor.own" \ No newline at end of file diff --git a/src/com/annimon/ownlang/Main.java b/src/com/annimon/ownlang/Main.java index 1da24f5..dbd6a8b 100644 --- a/src/com/annimon/ownlang/Main.java +++ b/src/com/annimon/ownlang/Main.java @@ -3,14 +3,13 @@ package com.annimon.ownlang; import com.annimon.ownlang.lib.CallStack; import com.annimon.ownlang.parser.Lexer; import com.annimon.ownlang.parser.Parser; +import com.annimon.ownlang.parser.SourceLoader; import com.annimon.ownlang.parser.Token; import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.visitors.AssignValidator; import com.annimon.ownlang.parser.visitors.FunctionAdder; import com.annimon.ownlang.parser.visitors.VariablePrinter; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.List; import java.util.concurrent.TimeUnit; @@ -21,7 +20,7 @@ public final class Main { public static void main(String[] args) throws IOException { if (args.length == 0) { - run(readFile("program.own"), true, true, true); + run(SourceLoader.readSource("program.own"), true, true, true); return; } @@ -47,7 +46,7 @@ public final class Main { case "-f": case "--file": if (i + 1 < args.length) { - input = readFile(args[i + 1]); + input = SourceLoader.readSource(args[i + 1]); i++; } break; @@ -62,10 +61,6 @@ public final class Main { run(input, showTokens, showAst, showMeasurements); } - private static String readFile(String file) throws IOException { - return new String( Files.readAllBytes(Paths.get(file)), "UTF-8"); - } - private static void run(String input, boolean showTokens, boolean showAst, boolean showMeasurements) { final TimeMeasurement measurement = new TimeMeasurement(); measurement.start("Tokenize time"); diff --git a/src/com/annimon/ownlang/parser/Lexer.java b/src/com/annimon/ownlang/parser/Lexer.java index f3c8c53..f37c32c 100644 --- a/src/com/annimon/ownlang/parser/Lexer.java +++ b/src/com/annimon/ownlang/parser/Lexer.java @@ -91,6 +91,7 @@ public final class Lexer { KEYWORDS.put("match", TokenType.MATCH); KEYWORDS.put("case", TokenType.CASE); KEYWORDS.put("extract", TokenType.EXTRACT); + KEYWORDS.put("include", TokenType.INCLUDE); } private final String input; diff --git a/src/com/annimon/ownlang/parser/Parser.java b/src/com/annimon/ownlang/parser/Parser.java index 89011f4..5710c15 100644 --- a/src/com/annimon/ownlang/parser/Parser.java +++ b/src/com/annimon/ownlang/parser/Parser.java @@ -129,6 +129,9 @@ public final class Parser { if (match(TokenType.USE)) { return new UseStatement(expression()); } + if (match(TokenType.INCLUDE)) { + return new IncludeStatement(expression()); + } if (match(TokenType.FOR)) { return forStatement(); } diff --git a/src/com/annimon/ownlang/parser/SourceLoader.java b/src/com/annimon/ownlang/parser/SourceLoader.java new file mode 100644 index 0000000..aed81e1 --- /dev/null +++ b/src/com/annimon/ownlang/parser/SourceLoader.java @@ -0,0 +1,30 @@ +package com.annimon.ownlang.parser; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public final class SourceLoader { + + public static String readSource(String name) throws IOException { + InputStream is = SourceLoader.class.getResourceAsStream(name); + if (is != null) return readStream(is); + + is = new FileInputStream(name); + return readStream(is); + } + + private static String readStream(InputStream is) throws IOException { + final StringBuilder text = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) { + String line; + while ((line = reader.readLine()) != null) { + text.append(line); + text.append(System.lineSeparator()); + } + } + return text.toString(); + } +} diff --git a/src/com/annimon/ownlang/parser/TokenType.java b/src/com/annimon/ownlang/parser/TokenType.java index c277896..347e474 100644 --- a/src/com/annimon/ownlang/parser/TokenType.java +++ b/src/com/annimon/ownlang/parser/TokenType.java @@ -27,6 +27,7 @@ public enum TokenType { MATCH, CASE, EXTRACT, + INCLUDE, PLUS, // + MINUS, // - diff --git a/src/com/annimon/ownlang/parser/ast/IncludeStatement.java b/src/com/annimon/ownlang/parser/ast/IncludeStatement.java new file mode 100644 index 0000000..1570d68 --- /dev/null +++ b/src/com/annimon/ownlang/parser/ast/IncludeStatement.java @@ -0,0 +1,47 @@ +package com.annimon.ownlang.parser.ast; + +import com.annimon.ownlang.parser.Lexer; +import com.annimon.ownlang.parser.Parser; +import com.annimon.ownlang.parser.SourceLoader; +import com.annimon.ownlang.parser.Token; +import com.annimon.ownlang.parser.visitors.FunctionAdder; +import java.util.List; + +/** + * + * @author aNNiMON + */ +public final class IncludeStatement implements Statement { + + public final Expression expression; + + public IncludeStatement(Expression expression) { + this.expression = expression; + } + + @Override + public void execute() { + try { + final String input = SourceLoader.readSource(expression.eval().asString()); + final List tokens = new Lexer(input).tokenize(); + final Parser parser = new Parser(tokens); + final Statement program = parser.parse(); + if (!parser.getParseErrors().hasErrors()) { + program.accept(new FunctionAdder()); + program.execute(); + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + @Override + public void accept(Visitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return "include " + expression; + } +} diff --git a/src/com/annimon/ownlang/parser/ast/Visitor.java b/src/com/annimon/ownlang/parser/ast/Visitor.java index 7ef79c6..31ad18c 100644 --- a/src/com/annimon/ownlang/parser/ast/Visitor.java +++ b/src/com/annimon/ownlang/parser/ast/Visitor.java @@ -24,6 +24,7 @@ public interface Visitor { void visit(ExprStatement s); void visit(FunctionalExpression s); void visit(IfStatement s); + void visit(IncludeStatement s); void visit(MapExpression s); void visit(MatchExpression s); void visit(PrintStatement s); diff --git a/src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java b/src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java index cc2c573..c669939 100644 --- a/src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java +++ b/src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java @@ -118,6 +118,11 @@ public abstract class AbstractVisitor implements Visitor { } } + @Override + public void visit(IncludeStatement s) { + s.expression.accept(this); + } + @Override public void visit(MapExpression s) { for (Map.Entry entry : s.elements.entrySet()) { diff --git a/visitor.own b/visitor.own index 9a9f6d8..e9548e6 100644 --- a/visitor.own +++ b/visitor.own @@ -1,5 +1,5 @@ -func() -def func() print "function\n" +function() +def function() print "function\n" a = 2 + 3 * 4 print a \ No newline at end of file