Commit 9ef005ee authored by Kevin Wu's avatar Kevin Wu

Add Scope and more nodes

parent b85b48fd
.idea/
Kythera.iml
out/
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="asm-7.1">
<CLASSES>
<root url="jar://$PROJECT_DIR$/../asm-7.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_12" default="false" project-jdk-name="12" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/Kythera.iml" filepath="$PROJECT_DIR$/.idea/Kythera.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
This diff is collapsed.
package io.kwu.kythera;
import io.kwu.kythera.parser.NodeType;
import java.util.HashMap;
public class Scope {
public final Scope parent;
private HashMap<String, NodeType> symbols = new HashMap<>();
public Scope() {
this.parent = null;
}
public Scope(Scope parent) {
this.parent = parent;
}
/**
* Initialize variable. Throws error if already declared
*/
public void create(String name, NodeType type) throws Exception {
if (this.symbols.containsKey(name)) {
throw new Exception(name + " is already bound.");
}
this.symbols.put(name, type);
}
/**
* Get type of variable
*/
public NodeType get(String name) {
if (this.symbols.containsKey(name)) {
return this.symbols.get(name);
} else {
if(this.parent == null) {
throw new Error(name + " is not defined.");
} else {
return this.parent.get(name);
}
}
}
/**
* true if variable is accessible in this scope (including its parents), false otherwise
*/
public boolean has(String name) {
if(symbols.containsKey(name)) {
return true;
} else {
if(this.parent == null) {
return false;
} else {
return this.parent.has(name);
}
}
}
}
......@@ -2,6 +2,8 @@ package io.kwu.kythera.parser;
/**
* Enum for core type categories.
* For non-scalar types, additional information is needed
* to fully describe and distinguish the type.
*/
public enum BaseType {
INT("int", true),
......@@ -9,10 +11,10 @@ public enum BaseType {
DOUBLE("double", true),
BOOL("bool", true),
TYPE("type", true), // type may not be scalar in the future
STRUCT("struct", false),
LIST("list", false),
TUPLE("tuple", false),
// LIST
// MAP
MAP("map", false),
STRUCT("struct", false),
FN("fn", false);
public final String name;
......
......@@ -7,10 +7,9 @@ import java.util.Map;
/**
* Parser's internal representation of a type.
* Distinct from a TypeLiteralNode (which represents and comes from syntax), though
* a NodeType can be constructed from a TypeLiteralNode.
* Distinct from a TypeLiteralNode (which represents and comes from syntax).
*
* Analogous to a ParseNode with type "type" in kythera-js.
* Analogous to a ParseNode with kind "type" in kythera-js.
*/
public class NodeType {
public final BaseType baseType;
......@@ -23,18 +22,26 @@ public class NodeType {
this.baseType = typeNode.baseType;
}
// TODO there might be a more elegant way to do this conversion
public String toString() {
return baseType.name;
}
// scalar types only need one NodeType instance, provided statically here
public String toString(int indent) {
// if called from a child class, will this use the overriding or parent implementation?
return this.toString().indent(indent);
}
// TODO there might be a more elegant way to do this conversion
// scalar types only need one instance for the whole parser, 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)
)
Map.ofEntries(
Map.entry(BaseType.INT, INT),
Map.entry(BaseType.BOOL, BOOL),
Map.entry(BaseType.TYPE, TYPE)
)
);
}
package io.kwu.kythera.parser;
import java.util.HashMap;
public class StructNodeType extends NodeType {
public final HashMap<String, NodeType> entries;
public StructNodeType(HashMap<String, NodeType> entries) {
super(BaseType.STRUCT);
this.entries = entries;
}
@Override
public boolean equals(Object other) {
if(!(other instanceof StructNodeType)) {
return false;
}
StructNodeType otherStructNodeType = (StructNodeType)other;
assert(otherStructNodeType.baseType.equals(BaseType.STRUCT));
return otherStructNodeType.entries.equals(this.entries);
}
}
\ No newline at end of file
......@@ -17,6 +17,8 @@ public class AssignNode extends ExpressionNode {
public AssignNode(Operator op, ExpressionNode left, ExpressionNode right) throws ParserException {
super(NodeKind.ASSIGN, right.type);
// TODO ensure that left node is an identifier or object member
if (!Arrays.asList(new Operator[]{
EQUALS,
PLUS_EQUALS,
......@@ -25,7 +27,7 @@ public class AssignNode extends ExpressionNode {
DIV_EQUALS,
MOD_EQUALS,
}).contains(op)) {
throw new ParserException("Invalid operator: " + op.symbol + " is not a valid assignment operator.");
throw new ParserException("Invalid operator: '" + op.symbol + "' is not a valid assignment operator.");
}
this.left = left;
......
......@@ -24,14 +24,14 @@ public class BlockNode extends ExpressionNode {
ExpressionNode lastNode = body[body.length - 1];
if(lastNode.kind != NodeKind.RETURN) {
returns.add(body[body.length - 1]); // if no return, block evaluates to last expression value
returns.add(lastNode); // if no return, block evaluates to last expression value
}
for(ExpressionNode e : body) {
if(returnType == null) {
returnType = e.type;
} else if(!e.type.equals(returnType)){
throw new ParserException("Type mismatch: Block returned " + returnType.toString() + " but later returned " + e.type.toString());
throw new ParserException("Type mismatch: Block returned " + returnType.toString() + " but later also returned " + e.type.toString());
}
}
......
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.BaseType;
import io.kwu.kythera.parser.NodeType;
import io.kwu.kythera.parser.ParserException;
public class BooleanLiteral {
public static final ScalarLiteralNode<Boolean> TRUE;
public static final ScalarLiteralNode<Boolean> FALSE;
static {
ScalarLiteralNode<Boolean> t;
ScalarLiteralNode<Boolean> f;
try {
t = new ScalarLiteralNode<>(NodeType.BOOL, true);
f = new ScalarLiteralNode<>(NodeType.BOOL, false);
} catch(ParserException e) {
System.err.println("Internal error: Could not initialize static boolean primitive:");
System.err.println(e);
t = null;
f = null;
}
TRUE = t;
FALSE = f;
}
}
package io.kwu.kythera.parser.node;
/**
* Access of compound type with brackets, e.g.
* myArray[0]
*/
public class BracketAccessNode extends ExpressionNode {
public final ExpressionNode target;
public final ExpressionNode key;
public BracketAccessNode(ExpressionNode target, ExpressionNode key) {
super(NodeKind.ACCESS);
this.target = target;
this.key = key;
}
}
package io.kwu.kythera.parser.node;
import io.kwu.kythera.parser.BaseType;
import io.kwu.kythera.parser.ParserException;
/**
* Node for access by dot, e.g.
* myObject.fieldName
*/
public class DotAccessNode extends ExpressionNode {
public final ExpressionNode target;
public final String key;
public DotAccessNode(ExpressionNode target, String key) throws ParserException {
super(NodeKind.ACCESS);
if(target.type.baseType != BaseType.STRUCT) {
throw new ParserException("Expected struct with field " + key + ", but found " + target.type.toString());
}
this.target = target;
this.key = key;
}
}
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