Skip to content
This repository has been archived by the owner on May 11, 2022. It is now read-only.

Commit

Permalink
Fix bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
Seggan committed Mar 4, 2022
1 parent c3a79d5 commit 1edf221
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 47 deletions.
2 changes: 1 addition & 1 deletion docs/differences.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Element | Difference
------- | ----------
`E` | The "eval Python" part of `E` evals Java, not Python. It loads the snippet into [JShell](https://en.wikipedia.org/wiki/JShell) and the pushes the result back onto the stack. The JShell instance is cached, meaning that the following code will push two zeros on the stack: ``` `int i = 0`E`i`E```
`` | `` can perform logarithms on complex numbers. It will also not operate on lists and vectorize instead
``` ` ``` | Normal, uncompressed strings are not decompressed if they do not contain ASCII characters
`¨U` | `¨U` decompresses compressed responses, unlike Vyxal

## Added Elements

Expand Down
4 changes: 4 additions & 0 deletions src/main/antlr/io/github/seggan/jyxal/antlr/VyxalLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,7 @@ SINGLE_CHAR_STRING
DOUBLE_CHAR_STRING
: ''
;
LITERALLY_ANY_TEXT
: [\u0010-\uFFFF]
;
40 changes: 18 additions & 22 deletions src/main/antlr/io/github/seggan/jyxal/antlr/VyxalParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ options {
}

file
: program EOF?
: program EOF
;

program
Expand All @@ -27,6 +27,22 @@ literal
| list
;

normal_string
: BACKTICK (~BACKTICK .)+? BACKTICK
;

compressed_string
: COMPRESSED_STRING (~COMPRESSED_STRING .)+? COMPRESSED_STRING
;

single_char_string
: SINGLE_CHAR_STRING .
;

double_char_string
: DOUBLE_CHAR_STRING . .
;

number
: integer (PERIOD integer)?
;
Expand All @@ -36,7 +52,7 @@ integer
;

compressed_number
: COMPRESSED_NUMBER any COMPRESSED_NUMBER
: COMPRESSED_NUMBER (~COMPRESSED_NUMBER .)+? COMPRESSED_NUMBER
;

complex_number
Expand All @@ -47,26 +63,6 @@ list
: LIST_OPEN program (PIPE program)* LIST_CLOSE?
;

normal_string
: BACKTICK any BACKTICK
;

compressed_string
: COMPRESSED_STRING any COMPRESSED_STRING
;

single_char_string
: SINGLE_CHAR_STRING .
;

double_char_string
: DOUBLE_CHAR_STRING . .
;

any
: .+?
;

statement
: if_statement
| for_loop
Expand Down
26 changes: 23 additions & 3 deletions src/main/java/io/github/seggan/jyxal/compiler/Compiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public final class Compiler extends VyxalParserBaseVisitor<Void> implements Opco
private final Set<String> contextVariables = new HashSet<>();

private final Deque<JyxalMethod> callStack = new ArrayDeque<>();
private final Deque<Loop> loopStack = new ArrayDeque<>();

private int listCounter = 0;
private int lambdaCounter = 0;
Expand Down Expand Up @@ -188,8 +189,9 @@ public Void visitComplex_number(VyxalParser.Complex_numberContext ctx) {
@Override
public Void visitNormal_string(VyxalParser.Normal_stringContext ctx) {
JyxalMethod mv = callStack.peek();
String text = ctx.getText();
mv.loadStack();
mv.visitLdcInsn(Compression.decompress(RuntimeHelpers.unescapeString(ctx.any().getText())));
mv.visitLdcInsn(Compression.decompress(RuntimeHelpers.unescapeString(text.substring(1, text.length() - 1))));
AsmHelper.push(mv);
return null;
}
Expand Down Expand Up @@ -352,7 +354,12 @@ public Void visitElement(VyxalParser.ElementContext ctx) {
Consumer<JyxalMethod> consumer = ctx.MODIFIER() == null ? null : visitModifier(ctx.MODIFIER().getText());

JyxalMethod mv = callStack.peek();
Element.getByText(element).compile(classWriter, mv);
if (element.equals("X")) {
Loop loop = loopStack.peek();
mv.visitJumpInsn(GOTO, loop.end);
} else {
Element.getByText(element).compile(classWriter, mv);
}

if (consumer != null) {
consumer.accept(mv);
Expand All @@ -367,6 +374,8 @@ public Void visitWhile_loop(VyxalParser.While_loopContext ctx) {
Label end = new Label();
int childIndex = 0;

loopStack.push(new Loop(start, end));

JyxalMethod mv = callStack.peek();
mv.visitLabel(start);
if (ctx.program().size() > 1) {
Expand All @@ -387,6 +396,8 @@ public Void visitWhile_loop(VyxalParser.While_loopContext ctx) {
mv.visitJumpInsn(GOTO, start);
mv.visitLabel(end);

loopStack.pop();

return null;
}

Expand All @@ -400,6 +411,8 @@ public Void visitFor_loop(VyxalParser.For_loopContext ctx) {
Label end = new Label();
JyxalMethod mv = callStack.peek();

loopStack.push(new Loop(start, end));

AsmHelper.pop(mv);
mv.visitMethodInsn(
INVOKESTATIC,
Expand Down Expand Up @@ -438,6 +451,8 @@ public Void visitFor_loop(VyxalParser.For_loopContext ctx) {
mv.visitLabel(end);
}

loopStack.pop();

return null;
}

Expand All @@ -446,6 +461,8 @@ public Void visitIf_statement(VyxalParser.If_statementContext ctx) {
JyxalMethod mv = callStack.peek();
Label end = new Label();

loopStack.push(new Loop(end, end));

AsmHelper.pop(mv);
mv.visitMethodInsn(
INVOKESTATIC,
Expand All @@ -471,6 +488,8 @@ public Void visitIf_statement(VyxalParser.If_statementContext ctx) {
mv.visitLabel(end);
}

loopStack.pop();

return null;
}

Expand Down Expand Up @@ -545,5 +564,6 @@ public Void visitLambda(VyxalParser.LambdaContext ctx) {
return null;
}


private static record Loop(Label start, Label end) {
}
}
24 changes: 24 additions & 0 deletions src/main/java/io/github/seggan/jyxal/compiler/Element.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,30 @@ public enum Element {
MULTI_COMMAND("\u2022"),
FUNCTION_CALL("\u2020"),
MULTIPLY("*"),
BOOLIFY("\u1E03", mv -> {
mv.loadStack();
AsmHelper.pop(mv);
mv.visitMethodInsn(
Opcodes.INVOKESTATIC,
"runtime/RuntimeHelpers",
"truthValue",
"(Ljava/lang/Object;)Z",
false
);
mv.visitInsn(Opcodes.I2L);
mv.visitMethodInsn(
Opcodes.INVOKESTATIC,
"runtime/math/BigComplex",
"valueOf",
"(J)Lruntime/math/BigComplex;",
false
);
AsmHelper.push(mv);
}),
MODULO_FORMAT("%"),
HEAD("h", false),
TAIL("t", false),
INCREMENT("\u203A", true),
HALVE("\u00BD"),
ALL("A", false),
CHR_ORD("C", true),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,22 +72,9 @@ public ContextualVariable reserveVar() {
max = var.index;
}
}
if (max == 0) {
ContextualVariable var = new ContextualVariable(ctxVar + 1, this);
reservedVars.add(var);
return var;
} else {
for (int i = ctxVar + 1; i < max; i++) {
ContextualVariable var = new ContextualVariable(i, this);
if (!reservedVars.contains(var)) {
reservedVars.add(var);
return var;
}
}
ContextualVariable var = new ContextualVariable(ctxVar + 1, this);
reservedVars.add(var);
return var;
}
ContextualVariable var = new ContextualVariable(max == 0 ? ctxVar + 1 : max + 1, this);
reservedVars.add(var);
return var;
}

void freeVar(ContextualVariable var) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ private String parseString() {

private void checkEnd() {
if (index == json.length()) {
throw new RuntimeException("Unexpected end of JSON string");
throw new RuntimeException("Unexpected end of JSON string '%s'".formatted(json));
}
}

Expand Down
84 changes: 82 additions & 2 deletions src/main/java/io/github/seggan/jyxal/runtime/RuntimeMethods.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Iterator;
Expand All @@ -24,10 +24,12 @@
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

// All return values must be either BigComplex, JyxalList, or String.
@SuppressWarnings("UnusedReturnValue")
public final class RuntimeMethods {

private static final LazyInit<Pattern> COMMA_PATTERN = new LazyInit<>(() -> Pattern.compile(","));
private static final LazyInit<Pattern> SPACE_PATTERN = new LazyInit<>(() -> Pattern.compile(" "));

private RuntimeMethods() {
}
Expand Down Expand Up @@ -136,10 +138,25 @@ public static Object functionCall(ProgramStack stack) {

public static Object getRequest(Object obj) throws IOException {
String url = obj.toString();
URLConnection connection = new URL(url).openConnection();
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = "http://" + url;
}
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestProperty("User-Agent", "Mozilla/5.0 Jyxal");
connection.setRequestProperty("Content-Type", "text/plain; charset=UTF-8");
connection.setInstanceFollowRedirects(true);
connection.connect();
int code = connection.getResponseCode();
if (code / 100 == 3) {
String location = connection.getHeaderField("Location");
if (location != null) {
return RuntimeMethods.getRequest(location);
} else {
throw new IOException("Redirect without location");
}
} else if (code / 100 != 2) {
return BigComplex.valueOf(code);
}
byte[] response;
try (InputStream inputStream = connection.getInputStream()) {
response = inputStream.readAllBytes();
Expand Down Expand Up @@ -180,6 +197,26 @@ public static Object halve(ProgramStack stack) {
}
}

public static Object head(Object obj) {
if (obj instanceof JyxalList list) {
return list.get(0);
} else {
if (obj.toString().length() > 0) {
return obj.toString().substring(0, 1);
} else {
return BigComplex.ZERO;
}
}
}

public static Object increment(Object obj) {
if (obj instanceof BigComplex c) {
return c.add(BigComplex.ONE);
} else {
return SPACE_PATTERN.get().matcher(obj.toString()).replaceAll("0");
}
}

public static Object infinitePrimes() {
return JyxalList.createInf(new Supplier<>() {
BigInteger next = BigInteger.ONE;
Expand Down Expand Up @@ -371,6 +408,27 @@ public static Object mapGetSet(ProgramStack stack) {
return BigComplex.ZERO;
}

public static Object moduloFormat(ProgramStack stack) {
Object o = RuntimeHelpers.vectorise(2, RuntimeMethods::multiCommand, stack);
if (o != null) return o;
Object b = stack.pop();
Object a = stack.pop();
if (a instanceof BigComplex ca && b instanceof BigComplex cb) {
// BigComplex has no mod method...
if (cb.isReal()) {
return BigComplex.valueOf(ca.re.remainder(cb.re), ca.im.remainder(cb.re));
} else {
throw new RuntimeException("Can't modulo complex numbers with non-real numbers");
}
} else {
if (a instanceof BigComplex) {
return b.toString().replace("%", a.toString());
} else {
return a.toString().replace("%", b.toString());
}
}
}

public static Object multiCommand(ProgramStack stack) {
Object o = RuntimeHelpers.vectorise(2, RuntimeMethods::multiCommand, stack);
if (o != null) return o;
Expand Down Expand Up @@ -511,6 +569,28 @@ public static Object splitOn(ProgramStack stack) {
}
}

public static Object tail(Object obj) {
if (obj instanceof JyxalList list) {
if (list.isLazy()) {
Iterator<Object> iterator = list.iterator();
Object last = BigComplex.ZERO;
while (iterator.hasNext()) {
last = iterator.next();
}
return last;
} else {
return list.get(list.size() - 1);
}
} else {
String s = obj.toString();
if (s.length() == 0) {
return BigComplex.ZERO;
} else {
return s.charAt(s.length() - 1);
}
}
}

public static Object triplicate(ProgramStack stack) {
Object obj = Objects.requireNonNull(stack.peek());
if (obj instanceof JyxalList jyxalList) {
Expand Down
Loading

0 comments on commit 1edf221

Please sign in to comment.