Skip to content

Commit c17d425

Browse files
committed
tcr/num: Introduce Num typeclass and Int64 type
Towards #6
1 parent b34f3b4 commit c17d425

File tree

14 files changed

+335
-56
lines changed

14 files changed

+335
-56
lines changed

src/main/antlr/xyz/leutgeb/lorenz/atlas/antlr/Splay.g4

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ expression : identifier # variableExpression
5454
| PAREN_OPEN expression PAREN_CLOSE # parenthesizedExpression
5555
| NUMBER # constant
5656
| left=expression op right=expression # comparison
57+
| left=expression arithOp right=expression # arithExpression
5758
| TILDE (numerator=NUMBER)? (DIV denominator=NUMBER)? expression # tickExpression
5859
| COIN (numerator=NUMBER)? (DIV denominator=NUMBER)? # coinExpression
5960
| UNDERSCORE # holeExpression
@@ -62,6 +63,8 @@ expression : identifier # variableExpression
6263

6364
op : EQ | NE | LT | LE | GT | GE ;
6465

66+
arithOp : PLUS | MINUS | CROSS | DIV ;
67+
6568
// For patterns we only admit simpler tuples:
6669
// - non-recursive, i.e. it is only possible to match one level of a tree
6770
// - no derived identifiers
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package xyz.leutgeb.lorenz.atlas.ast;
2+
3+
import java.io.PrintStream;
4+
import java.util.Collections;
5+
import java.util.List;
6+
import java.util.function.BiFunction;
7+
8+
import static java.util.function.Predicate.isEqual;
9+
10+
public enum ArithmeticOperator {
11+
PLUS(List.of("+")),
12+
MINUS(List.of("-")),
13+
TIMES(List.of("*", "⨯")),
14+
DIV(List.of("/"));
15+
16+
private final List<String> tokens;
17+
18+
ArithmeticOperator(List<String> tokens) {
19+
if (tokens.isEmpty()) {
20+
throw new IllegalArgumentException();
21+
}
22+
this.tokens = Collections.unmodifiableList(tokens);
23+
}
24+
25+
public static ArithmeticOperator fromToken(String token) {
26+
for (ArithmeticOperator op : ArithmeticOperator.values()) {
27+
if (op.tokens.stream().anyMatch(isEqual(token))) {
28+
return op;
29+
}
30+
}
31+
throw new IllegalArgumentException();
32+
}
33+
34+
public void printTo(PrintStream out) {
35+
out.print(tokens.get(0));
36+
}
37+
38+
public void printHaskellTo(PrintStream out) {
39+
printTo(out);
40+
}
41+
42+
public void printJavaTo(String x, String y, PrintStream out) {
43+
out.print(x);
44+
out.print(" ");
45+
printTo(out);
46+
out.print(" ");
47+
out.print(y);
48+
}
49+
50+
@Override
51+
public String toString() {
52+
return tokens.get(0);
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package xyz.leutgeb.lorenz.atlas.ast.expressions;
2+
3+
import lombok.EqualsAndHashCode;
4+
import lombok.NonNull;
5+
import lombok.Value;
6+
import xyz.leutgeb.lorenz.atlas.ast.ArithmeticOperator;
7+
import xyz.leutgeb.lorenz.atlas.ast.Normalization;
8+
import xyz.leutgeb.lorenz.atlas.ast.sources.Derived;
9+
import xyz.leutgeb.lorenz.atlas.ast.sources.Source;
10+
import xyz.leutgeb.lorenz.atlas.typing.simple.TypeClass;
11+
import xyz.leutgeb.lorenz.atlas.typing.simple.TypeConstraint;
12+
import xyz.leutgeb.lorenz.atlas.typing.simple.TypeError;
13+
import xyz.leutgeb.lorenz.atlas.typing.simple.types.BoolType;
14+
import xyz.leutgeb.lorenz.atlas.typing.simple.types.Type;
15+
import xyz.leutgeb.lorenz.atlas.unification.UnificationContext;
16+
import xyz.leutgeb.lorenz.atlas.util.IntIdGenerator;
17+
18+
import java.io.PrintStream;
19+
import java.util.Map;
20+
import java.util.Stack;
21+
import java.util.stream.Stream;
22+
23+
@Value
24+
@EqualsAndHashCode(callSuper = true)
25+
public class ArithmeticExpression extends Expression {
26+
27+
@NonNull Expression left;
28+
@NonNull ArithmeticOperator operator;
29+
@NonNull Expression right;
30+
31+
public ArithmeticExpression(
32+
Source source,
33+
@NonNull Expression left,
34+
@NonNull ArithmeticOperator operator,
35+
@NonNull Expression right) {
36+
super(source);
37+
this.left = left;
38+
this.operator = operator;
39+
this.right = right;
40+
}
41+
42+
private ArithmeticExpression(
43+
Source source, Expression left, ArithmeticOperator operator, Expression right, Type type) {
44+
super(source);
45+
this.left = left;
46+
this.operator = operator;
47+
this.right = right;
48+
this.type = type;
49+
}
50+
51+
@Override
52+
public Stream<? extends Expression> getChildren() {
53+
return Stream.of(left, right);
54+
}
55+
56+
@Override
57+
public Type inferInternal(UnificationContext context) throws TypeError {
58+
var ty = context.fresh();
59+
context.addEquivalenceIfNotEqual(right.infer(context), ty, source);
60+
context.addEquivalenceIfNotEqual(left.infer(context), ty, source);
61+
context
62+
.getSignature(context.getFunctionInScope(), source)
63+
.addConstraint(new TypeConstraint(TypeClass.NUM, ty));
64+
return ty;
65+
}
66+
67+
@Override
68+
public Expression normalize(Stack<Normalization> context, IntIdGenerator idGenerator) {
69+
// TODO(lorenzleutgeb): Only create new expression if necessary!
70+
return new ArithmeticExpression(
71+
Derived.anf(this),
72+
left.normalize(context, idGenerator),
73+
operator,
74+
right.normalize(context, idGenerator));
75+
}
76+
77+
@Override
78+
public void printTo(PrintStream out, int indentation) {
79+
left.printTo(out, indentation);
80+
out.print(" ");
81+
operator.printTo(out);
82+
out.print(" ");
83+
right.printTo(out, indentation);
84+
}
85+
86+
@Override
87+
public void printHaskellTo(PrintStream out, int indentation, String currentFunction) {
88+
left.printHaskellTo(out, indentation, currentFunction);
89+
out.print(" ");
90+
operator.printHaskellTo(out);
91+
out.print(" ");
92+
right.printHaskellTo(out, indentation, currentFunction);
93+
}
94+
95+
@Override
96+
public void printJavaTo(PrintStream out, int indentation, String currentFunction) {
97+
operator.printJavaTo(
98+
((IdentifierExpression) left).getName(), ((IdentifierExpression) right).getName(), out);
99+
}
100+
101+
@Override
102+
public Expression unshare(IntIdGenerator idGenerator, boolean lazy) {
103+
return this;
104+
}
105+
106+
@Override
107+
public boolean isImmediate() {
108+
return false;
109+
}
110+
111+
@Override
112+
public Expression rename(Map<String, String> renaming) {
113+
if (freeVariables().stream()
114+
.map(IdentifierExpression::getName)
115+
.anyMatch(renaming::containsKey)) {
116+
return new ArithmeticExpression(
117+
Derived.rename(this), left.rename(renaming), operator, right.rename(renaming), type);
118+
}
119+
return this;
120+
}
121+
122+
@Override
123+
public String toString() {
124+
return left + " " + operator + " " + right;
125+
}
126+
127+
@Override
128+
public boolean isTerminal() {
129+
return true;
130+
}
131+
}

src/main/java/xyz/leutgeb/lorenz/atlas/ast/expressions/BooleanExpression.java

-4
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,6 @@ public Stream<? extends Expression> getChildren() {
5757

5858
@Override
5959
public Type inferInternal(UnificationContext context) throws TypeError {
60-
// The next two lines hide polymorphism in favor of the "abstract base signature".
61-
// context.add(right.infer(context), BaseType.INSTANCE);
62-
// context.add(left.infer(context), BaseType.INSTANCE);
63-
6460
var ty = context.fresh();
6561
context.addEquivalenceIfNotEqual(right.infer(context), ty, source);
6662
context.addEquivalenceIfNotEqual(left.infer(context), ty, source);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package xyz.leutgeb.lorenz.atlas.ast.expressions;
2+
3+
import lombok.EqualsAndHashCode;
4+
import lombok.NonNull;
5+
import lombok.Value;
6+
import xyz.leutgeb.lorenz.atlas.ast.sources.Source;
7+
import xyz.leutgeb.lorenz.atlas.typing.simple.TypeClass;
8+
import xyz.leutgeb.lorenz.atlas.typing.simple.TypeConstraint;
9+
import xyz.leutgeb.lorenz.atlas.typing.simple.TypeError;
10+
import xyz.leutgeb.lorenz.atlas.typing.simple.types.Type;
11+
import xyz.leutgeb.lorenz.atlas.unification.UnificationContext;
12+
import xyz.leutgeb.lorenz.atlas.util.IntIdGenerator;
13+
14+
import java.util.stream.Stream;
15+
16+
@Value
17+
@EqualsAndHashCode(callSuper = true)
18+
public class NumberExpression extends Expression {
19+
@NonNull String number;
20+
21+
public NumberExpression(String number, Source source) {
22+
super(source);
23+
this.number = number;
24+
}
25+
26+
@Override
27+
protected Stream<? extends Expression> getChildren() {
28+
return Stream.of();
29+
}
30+
31+
@Override
32+
protected Type inferInternal(UnificationContext context) throws TypeError {
33+
var ty = context.fresh();
34+
context
35+
.getSignature(context.getFunctionInScope(), source)
36+
.addConstraint(new TypeConstraint(TypeClass.NUM, ty));
37+
return ty;
38+
}
39+
40+
@Override
41+
public Expression unshare(IntIdGenerator idGenerator, boolean lazy) {
42+
return this;
43+
}
44+
45+
@Override
46+
public boolean isImmediate() {
47+
return true;
48+
}
49+
}

src/main/java/xyz/leutgeb/lorenz/atlas/ast/visitors/ExpressionVisitor.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ public Expression visitComparison(SplayParser.ComparisonContext ctx) {
6464
getSource(ctx), l, ComparisonOperator.fromToken(ctx.op().getText()), r);
6565
}
6666

67+
@Override
68+
public Expression visitArithExpression(SplayParser.ArithExpressionContext ctx) {
69+
var l = ExpressionVisitor.this.visit(ctx.left);
70+
var r = ExpressionVisitor.this.visit(ctx.right);
71+
return new ArithmeticExpression(
72+
getSource(ctx), l, ArithmeticOperator.fromToken(ctx.arithOp().getText()), r);
73+
}
74+
6775
@Override
6876
public Expression visitMatchExpression(SplayParser.MatchExpressionContext ctx) {
6977
return new MatchTreeExpression(
@@ -154,6 +162,6 @@ public Expression visitParenthesizedExpression(SplayParser.ParenthesizedExpressi
154162

155163
@Override
156164
public Expression visitConstant(SplayParser.ConstantContext ctx) {
157-
throw new UnsupportedOperationException("literal numbers are not implemented");
165+
return new NumberExpression(ctx.getText(), getSource(ctx));
158166
}
159167
}

src/main/java/xyz/leutgeb/lorenz/atlas/commands/Haskell.java

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public void run() {
7474
stream.println();
7575
stream.println("module " + lastModulePart + " where");
7676
stream.println("import InterpreterPrelude (Tree(Node, Leaf))");
77+
stream.println("import Data.Int (Int64)");
7778
stream.println();
7879
for (String imp : imports.get(e)) {
7980
stream.println("import qualified " + imp);

src/main/java/xyz/leutgeb/lorenz/atlas/module/ModuleParser.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
class ModuleParser {
2121
public static List<FunctionDefinition> parse(String s, String moduleName) {
2222
try {
23-
return parse(CharStreams.fromString(s), moduleName);
23+
return parse(CharStreams.fromString(s, "inline"), moduleName);
2424
// } catch (IOException e) {
2525
// In this case we assume that something went fundamentally
2626
// wrong when using a String as input. The caller probably

src/main/java/xyz/leutgeb/lorenz/atlas/typing/simple/FunctionSignature.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ public String toString() {
9696

9797
sb.append(type.getFrom());
9898

99-
sb.append(" → ");
99+
if (type.getFrom().size() > 0) {
100+
sb.append(" → ");
101+
}
100102
sb.append(type.getTo());
101103

102104
if (annotation.isPresent()) {

src/main/java/xyz/leutgeb/lorenz/atlas/typing/simple/TypeClass.java

+3
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55

66
import java.util.Set;
77
import lombok.Value;
8+
import xyz.leutgeb.lorenz.atlas.typing.simple.types.Type;
89

910
@Value
1011
public class TypeClass {
1112
public static TypeClass EQ = new TypeClass("Eq", 1, emptySet());
1213
public static TypeClass ORD = new TypeClass("Ord", 1, singleton(TypeClass.EQ));
1314

15+
public static TypeClass NUM = new TypeClass("Num", 1, emptySet());
16+
1417
String name;
1518
int arity;
1619

src/main/java/xyz/leutgeb/lorenz/atlas/typing/simple/types/BaseType.java

-24
This file was deleted.

0 commit comments

Comments
 (0)