Skip to content

Commit 896f76c

Browse files
committed
Use relative path in include statement
1 parent b3950ec commit 896f76c

File tree

14 files changed

+51
-22
lines changed

14 files changed

+51
-22
lines changed

docs/docs/en/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Changes
66
- Add `own` package manager. Usage examples: `own`, `own init`, `own add openai`.
7+
- Use relative path in include statement.
78

89
### Fixes
910
- Fix passing command-line arguments to scripts.

docs/docs/ru/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Изменения
66
- Добавлен `own` пакетный менеджер. Примеры испльзования: `own`, `own init`, `own add openai`.
7+
- Относительные пути в include.
78

89
### Исправления
910
- Исправлена передача аргументов командной строки скриптам.

ownlang-core/src/main/java/com/annimon/ownlang/util/SourceLocationFormatterStage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public String perform(StagesData stagesData, Range input) {
1919

2020
static void printPosition(StringBuilder sb, Range range, String[] lines) {
2121
final Pos start = range.start();
22-
final int linesCount = lines.length;;
22+
final int linesCount = lines.length;
2323
if (range.isOnSameLine()) {
2424
if (start.row() < linesCount) {
2525
sb.append(lines[start.row()]);

ownlang-core/src/main/java/com/annimon/ownlang/util/input/InputSource.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ public interface InputSource {
88
String load() throws IOException;
99

1010
default String getBasePath() {
11-
int i = getPath().lastIndexOf("/");
11+
final String normalizedPath = getPath().replace("\\", "/");
12+
int i = normalizedPath.lastIndexOf("/");
1213
if (i == -1) return "";
13-
return getPath().substring(0, i + 1);
14+
return normalizedPath.substring(0, i + 1);
1415
}
1516
}

ownlang-core/src/main/java/com/annimon/ownlang/util/input/InputSourceDetector.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,29 @@
33
import java.nio.file.Files;
44
import java.nio.file.Path;
55

6-
public record InputSourceDetector() {
6+
public record InputSourceDetector(String basePath) {
77
public static final String RESOURCE_PREFIX = "resource:";
88

9+
public InputSourceDetector() {
10+
this("");
11+
}
12+
913
public boolean isReadable(String programPath) {
1014
if (programPath.startsWith(RESOURCE_PREFIX)) {
1115
String path = programPath.substring(RESOURCE_PREFIX.length());
12-
return getClass().getResource(path) != null;
16+
return getClass().getResource(basePath + path) != null;
1317
} else {
14-
Path path = Path.of(programPath);
18+
Path path = Path.of(basePath, programPath);
1519
return Files.isReadable(path) && Files.isRegularFile(path);
1620
}
1721
}
1822

1923
public InputSource toInputSource(String programPath) {
2024
if (programPath.startsWith(RESOURCE_PREFIX)) {
2125
String path = programPath.substring(RESOURCE_PREFIX.length());
22-
return new InputSourceResource(path);
26+
return new InputSourceResource(basePath + path);
2327
} else {
24-
return new InputSourceFile(programPath);
28+
return new InputSourceFile(basePath + programPath);
2529
}
2630
}
2731
}

ownlang-core/src/main/java/com/annimon/ownlang/util/input/SourceLoaderStage.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
public class SourceLoaderStage implements Stage<InputSource, String> {
1212

13+
public static final String TAG_BASE_PATH = "basePath";
1314
public static final String TAG_SOURCE_LINES = "sourceLines";
1415

1516
@Override
@@ -20,6 +21,7 @@ public String perform(StagesData stagesData, InputSource inputSource) {
2021
? new String[0]
2122
: result.split("\r?\n");
2223
stagesData.put(TAG_SOURCE_LINES, lines);
24+
stagesData.put(TAG_BASE_PATH, inputSource.getBasePath());
2325
return result;
2426
} catch (IOException e) {
2527
throw new OwnLangRuntimeException("Unable to read input " + inputSource, e);

ownlang-parser/src/main/java/com/annimon/ownlang/parser/Parser.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public static Node parse(List<Token> tokens) {
6161
private final List<Token> tokens;
6262
private final int size;
6363
private final ParseErrors parseErrors;
64+
private ParserMetadata metadata;
6465
private Statement parsedStatement;
6566

6667
private int index;
@@ -79,6 +80,10 @@ public ParseErrors getParseErrors() {
7980
return parseErrors;
8081
}
8182

83+
public void setMetadata(ParserMetadata metadata) {
84+
this.metadata = metadata;
85+
}
86+
8287
public Node parse() {
8388
parseErrors.clear();
8489
final BlockStatement result = new BlockStatement();
@@ -177,7 +182,8 @@ private Statement statement() {
177182

178183
private IncludeStatement includeStatement() {
179184
final var startTokenIndex = index - 1;
180-
final var include = new IncludeStatement(expression());
185+
final String basePath = (metadata != null) ? metadata.basePath() : "";
186+
final var include = new IncludeStatement(expression(), basePath);
181187
include.setRange(getRange(startTokenIndex, index));
182188
return include;
183189
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.annimon.ownlang.parser;
2+
3+
public record ParserMetadata(
4+
String basePath
5+
) {
6+
}

ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/IncludeStatement.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
public final class IncludeStatement extends InterruptableNode implements Statement, SourceLocation {
1919

2020
public final Node expression;
21+
public final String basePath;
2122
private final InputSourceDetector inputSourceDetector;
2223
private Range range;
2324

24-
public IncludeStatement(Node expression) {
25+
public IncludeStatement(Node expression, String basePath) {
2526
this.expression = expression;
26-
inputSourceDetector = new InputSourceDetector();
27+
this.basePath = basePath;
28+
inputSourceDetector = new InputSourceDetector(basePath);
2729
}
2830

2931
public void setRange(Range range) {

ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/IncludeSourceValidator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
final class IncludeSourceValidator extends LintVisitor {
1212
private final InputSourceDetector detector;
1313

14-
IncludeSourceValidator(LinterResults results) {
14+
IncludeSourceValidator(LinterResults results, String basePath) {
1515
super(results);
16-
detector = new InputSourceDetector();
16+
detector = new InputSourceDetector(basePath);
1717
}
1818

1919
@Override

ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LinterStage.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.annimon.ownlang.parser.ast.Visitor;
88
import com.annimon.ownlang.stages.Stage;
99
import com.annimon.ownlang.stages.StagesData;
10+
import com.annimon.ownlang.util.input.SourceLoaderStage;
1011
import java.util.ArrayList;
1112
import java.util.Comparator;
1213
import java.util.List;
@@ -26,7 +27,8 @@ public Node perform(StagesData stagesData, Node input) {
2627

2728
final LinterResults results = new LinterResults();
2829
final List<Visitor> validators = new ArrayList<>();
29-
validators.add(new IncludeSourceValidator(results));
30+
String basePath = stagesData.getOrDefault(SourceLoaderStage.TAG_BASE_PATH, "");
31+
validators.add(new IncludeSourceValidator(results, basePath));
3032
validators.add(new LoopStatementsValidator(results));
3133

3234
if (mode == Mode.SEMANTIC || mode == Mode.INTERNAL) {

ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ public Node visit(ArrayExpression s, T t) {
3030
public Node visit(AssignmentExpression s, T t) {
3131
final Node exprNode = s.expression.accept(this, t);
3232
final Node targetNode = s.target.accept(this, t);
33-
if ( (exprNode != s.expression || targetNode != s.target) && (targetNode instanceof Accessible) ) {
34-
return new AssignmentExpression(s.operation, (Accessible) targetNode, exprNode, s.getRange());
33+
if ( (exprNode != s.expression || targetNode != s.target) && (targetNode instanceof Accessible acc) ) {
34+
return new AssignmentExpression(s.operation, acc, exprNode, s.getRange());
3535
}
3636
return s;
3737
}
@@ -254,7 +254,7 @@ public Node visit(IfStatement s, T t) {
254254
public Node visit(IncludeStatement s, T t) {
255255
final Node expression = s.expression.accept(this, t);
256256
if (expression != s.expression) {
257-
return new IncludeStatement(expression);
257+
return new IncludeStatement(expression, s.basePath);
258258
}
259259
return s;
260260
}

ownlang-parser/src/main/java/com/annimon/ownlang/stages/ParserStage.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import com.annimon.ownlang.exceptions.OwnLangParserException;
44
import com.annimon.ownlang.parser.Parser;
5+
import com.annimon.ownlang.parser.ParserMetadata;
56
import com.annimon.ownlang.parser.Token;
67
import com.annimon.ownlang.parser.ast.Node;
8+
import com.annimon.ownlang.util.input.SourceLoaderStage;
79
import java.util.List;
810

911
public class ParserStage implements Stage<List<Token>, Node> {
@@ -14,6 +16,8 @@ public class ParserStage implements Stage<List<Token>, Node> {
1416
@Override
1517
public Node perform(StagesData stagesData, List<Token> input) {
1618
final Parser parser = new Parser(input);
19+
String basePath = stagesData.getOrDefault(SourceLoaderStage.TAG_BASE_PATH, "");
20+
parser.setMetadata(new ParserMetadata(basePath));
1721
final Node program = parser.parse();
1822
final var parseErrors = parser.getParseErrors();
1923
stagesData.put(TAG_PROGRAM, program);
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std
22

33
def testIncludeClass() {
4-
include "src/test/resources/expressions/includeClass.own.txt"
4+
include "includeClass.own.txt"
55
obj = new IncludeClass()
66
assertEquals("1", obj.field1)
77
assertEquals(2, obj.field2)
@@ -10,26 +10,26 @@ def testIncludeClass() {
1010

1111
def testIncludeNotExistsSource() {
1212
assertFail(def() {
13-
include "src/test.own"
13+
include "test.own"
1414
})
1515
}
1616

1717
def testCatchingIncludeNotExistsSource() {
1818
res = try(def() {
19-
include "src/test.own"
19+
include "test.own"
2020
}, def(classname, message) = "ok")
2121
assertEquals("ok", res)
2222
}
2323

2424
def testIncludeParseErrorSource() {
2525
assertFail(def() {
26-
include "src/test/resources/expressions/includeParseErrorSource.own.txt"
26+
include "includeParseErrorSource.own.txt"
2727
})
2828
}
2929

3030
def testCatchingIncludeParseErrorSource() {
3131
res = try(def() {
32-
include "src/test/resources/expressions/includeParseErrorSource.own.txt"
32+
include "includeParseErrorSource.own.txt"
3333
}, def(classname, message) = "ok")
3434
assertEquals("ok", res)
3535
}

0 commit comments

Comments
 (0)