Commit ebe2372c authored by Kevin Wu's avatar Kevin Wu

Add literal nodes, node types, and supporting code

parent cbd872ae
package io.kwu.kythera.parser;
/**
* Enum for core type categories.
*/
public enum BaseType {
INT("int", true),
FLOAT("float", true),
DOUBLE("double", true),
BOOL("bool", true),
TYPE("type", true), // type may not be scalar in the future
STRUCT("struct", false),
TUPLE("tuple", false);
// LIST
// MAP
public final String name;
public final boolean scalar;
BaseType(String name, boolean scalar) {
this.name = name;
this.scalar = scalar;
}
}
......@@ -5,7 +5,7 @@ package io.kwu.kythera.parser;
* Ported almost verbatim from the JS implementation, can probably be
* made more Java-idiomatic
*/
public class InputStream {
public final class InputStream {
private String input;
private int pos;
......
package io.kwu.kythera.parser;
import io.kwu.kythera.parser.node.TypeLiteralNode;
import java.util.Collections;
import java.util.Map;
/**
* Parser's internal representation of a type.
* Distinct from a TypeLiteralNode (which comes from syntax), though
* a NodeType can be constructed from a TypeLiteralNode.
*/
public class NodeType {
public final BaseType baseType;
public NodeType(BaseType baseType) {
this.baseType = baseType;
}
public NodeType(TypeLiteralNode typeNode) {
this.baseType = typeNode.baseType;
}
// TODO there might be a more elegant way to do this conversion
// scalar types only need one NodeType instance, provided statically here
public static NodeType INT = new NodeType(BaseType.INT);
public static NodeType BOOL = new NodeType(BaseType.BOOL);
public static NodeType TYPE = new NodeType(BaseType.TYPE);
public static final Map<BaseType, NodeType> fromBaseType = Collections.unmodifiableMap(
Map.ofEntries(
Map.entry(BaseType.INT, INT),
Map.entry(BaseType.BOOL, BOOL),
Map.entry(BaseType.TYPE, TYPE)
)
);
}
package io.kwu.kythera.parser;
// TODO are these all named after their symbols, or what they do?
public enum Operator {
// assignments
EQUALS("=", 1),
PLUS_EQUALS("+=", 1),
MINUS_EQUALS("-=", 1),
......@@ -8,21 +10,24 @@ public enum Operator {
DIV_EQUALS("/=", 1),
MOD_EQUALS("%=", 1),
// boolean logical
OR_LOGICAL("||", 3),
AND_LOGICAL("&&", 4),
// TODO bitwise boolean operators
// comparison
EQUIVALENT("==", 8),
NOT_EQUIV("!=", 8),
LESS_THAN("<", 9),
GREATER_THAN(">", 9),
LESS_EQUALS("<=", 9),
GREATER_EQUALS(">=", 9),
LESS_EQUIV("<=", 9),
GREATER_EQUIV(">=", 9),
// TODO bit shift operators
// arithmetic
PLUS("+", 11),
MINUS("-", 11),
......
package io.kwu.kythera.parser;
public class Parser {
public final class Parser {
public Parser() {
}
......
package io.kwu.kythera.parser;
public class Token {
public final class Token {
public final TokenType tokentype;
public final String value;
......
package io.kwu.kythera.parser;
import javax.crypto.spec.OAEPParameterSpec;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import static io.kwu.kythera.parser.TokenType.*;
public class Tokenizer {
public final class Tokenizer {
final static String[] KEYWORDS = {
"let",
"new", // declaration
......
package io.kwu.kythera.parser;
// placeholder until type system can be decided on
public enum Type {
}
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.Operator;
import io.kwu.kythera.parser.ParserException;
import static io.kwu.kythera.parser.Operator.*;
import java.util.Arrays;
/**
* Node for any assignment symbol
*/
public class AssignNode extends ExpressionNode {
public final ExpressionNode left;
public final ExpressionNode right;
public AssignNode(Operator op, ExpressionNode left, ExpressionNode right) throws ParserException {
super(NodeKind.ASSIGN, right.type);
if (!Arrays.asList(new Operator[]{
EQUALS,
PLUS_EQUALS,
MINUS_EQUALS,
TIMES_EQUALS,
DIV_EQUALS,
MOD_EQUALS,
}).contains(op)) {
throw new ParserException("Invalid operator: " + op.symbol + " is not a valid assignment operator.");
}
this.left = left;
this.right = right;
}
}
package io.kwu.kythera.parser.node;
public class Assignment {
}
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.Operator;
import static io.kwu.kythera.parser.Operator.*;
import io.kwu.kythera.parser.ParserException;
public class BinaryNode extends ExpressionNode {
import java.util.Arrays;
public final class BinaryNode extends ExpressionNode {
public final Operator op;
public final ExpressionNode left;
public final ExpressionNode right;
public BinaryNode(Operator op, ExpressionNode left, ExpressionNode right) {
public BinaryNode(Operator op, ExpressionNode left, ExpressionNode right) throws ParserException {
super(NodeKind.BINARY, null);
if (!Arrays.asList(new Operator[] {
EQUIVALENT,
NOT_EQUIV,
LESS_EQUIV,
GREATER_EQUIV,
GREATER_THAN,
LESS_THAN,
PLUS,
MINUS,
TIMES,
DIVIDE,
MODULUS,
OR_LOGICAL,
AND_LOGICAL,
}).contains(op)) {
throw new ParserException("Invalid operator: " + op.symbol + " cannot be used in a binary expression.");
}
this.op = op;
this.left = left;
this.right = right;
// TODO type check left and right?
// TODO type check left and right
this.type = left.type;
}
}
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.ParserException;
import io.kwu.kythera.parser.Type;
import io.kwu.kythera.parser.NodeType;
// ExpressionNodes are statements that evaluate to a value and therefore also have a type.
/**
* ExpressionNodes are statements that evaluate to a value and therefore also have a type.
*/
public abstract class ExpressionNode extends StatementNode {
public Type type; // may need to be set after ExpressionNode is instantiated
public NodeType type; // may need to be set after ExpressionNode is instantiated
ExpressionNode(NodeKind kind, Type type) throws ParserException {
ExpressionNode(NodeKind kind, NodeType type) {
super(kind);
this.type = type;
}
......
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.ParserException;
import io.kwu.kythera.parser.NodeType;
public class IdentifierNode extends ExpressionNode {
public final String name;
public IdentifierNode(String name, NodeType type) throws ParserException {
super(NodeKind.IDENTIFIER, type);
this.name = name;
}
}
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.ParserException;
public class LetNode extends StatementNode{
public final String identifier;
public final ExpressionNode target;
public LetNode(String identifier, ExpressionNode target) throws ParserException {
super(NodeKind.LET);
this.identifier = identifier;
this.target = target;
}
}
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.NodeType;
public abstract class LiteralNode extends ExpressionNode {
public LiteralNode(NodeType type) {
super(NodeKind.LITERAL, type);
}
}
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.NodeType;
import io.kwu.kythera.parser.ParserException;
public class NewNode extends ExpressionNode {
public NewNode(TypeLiteralNode target) throws ParserException {
super(NodeKind.NEW, new NodeType(target));
}
}
......@@ -5,7 +5,6 @@ public enum NodeKind {
BINARY,
ASSIGN,
LITERAL,
TYPE,
IDENTIFIER,
TYPEOF,
NEW,
......
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.BaseType;
/**
* For scalar type literals (e.g. int, bool)
*/
public final class PrimitiveTypeLiteral {
public final static class PrimitiveTypeLiteralNode extends TypeLiteralNode {
PrimitiveTypeLiteralNode(BaseType type) {
super(type);
}
}
public static PrimitiveTypeLiteralNode INT = new PrimitiveTypeLiteralNode(BaseType.INT);
public static PrimitiveTypeLiteralNode TYPE = new PrimitiveTypeLiteralNode(BaseType.TYPE);
}
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.BaseType;
import io.kwu.kythera.parser.NodeType;
import io.kwu.kythera.parser.ParserException;
/**
* For scalar literals (e.g. 0, true)
*/
public class ScalarLiteralNode<V> extends LiteralNode {
public final V value;
public ScalarLiteralNode(NodeType type, V value) throws ParserException {
super(type);
if(!type.baseType.scalar) {
throw new ParserException(type.baseType.name + " is not a scalar type.");
}
this.value = value;
}
}
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.ParserException;
// All nodes extend StatementNode. Statements have no type, so neither do StatementNodes.
// Very few StatementNodes are /not/ ParseNodes. Examples include "let" and "return".
/**
* All nodes extend StatementNode. Statements do not evaluate to a value, so they have no type.
* Most StatementNodes extend ExpressionNode. Exceptions include "let" and "return".
*/
// TODO this could be a good place to send line/col numbers for debugging
public abstract class StatementNode {
public final NodeKind kind;
public StatementNode(NodeKind kind) throws ParserException {
public StatementNode(NodeKind kind) {
this.kind = kind;
}
}
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.BaseType;
import io.kwu.kythera.parser.NodeType;
/**
* Comes from a type literal in syntax.
*/
public abstract class TypeLiteralNode extends LiteralNode {
public final BaseType baseType;
public TypeLiteralNode(BaseType baseType) {
super(NodeType.fromBaseType.get(baseType));
this.baseType = baseType;
}
}
......@@ -11,7 +11,7 @@ public class UnaryNode extends ExpressionNode {
super(NodeKind.UNARY, target.type);
if(op != Operator.NOT) {
throw new ParserException("Invalid operator: " + op.symbol);
throw new ParserException("Invalid operator: " + op.symbol + " cannot be used as a unary operator.");
}
this.operator = op;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment