generated from rnentjes/kotlin-server-web-undertow
Remove legacy JVM-specific file system, shell, and related implementations; migrate to platform-agnostic and common main modules.
This commit is contained in:
19
src/jvmMain/java/mtmc/lang/CompilationException.java
Normal file
19
src/jvmMain/java/mtmc/lang/CompilationException.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package mtmc.lang;
|
||||
|
||||
public class CompilationException extends Exception {
|
||||
protected Span span;
|
||||
|
||||
public CompilationException(String message, Span span) {
|
||||
super(message);
|
||||
this.span = span;
|
||||
}
|
||||
|
||||
public CompilationException(CompilationException parent, String message) {
|
||||
super(message, parent);
|
||||
this.span = parent.span;
|
||||
}
|
||||
|
||||
public Span getSpan() {
|
||||
return span;
|
||||
}
|
||||
}
|
||||
7
src/jvmMain/java/mtmc/lang/Language.java
Normal file
7
src/jvmMain/java/mtmc/lang/Language.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package mtmc.lang;
|
||||
|
||||
import mtmc.os.exec.Executable;
|
||||
|
||||
public interface Language {
|
||||
Executable compileExecutable(String filename, String source) throws ParseException, CompilationException;
|
||||
}
|
||||
55
src/jvmMain/java/mtmc/lang/Location.java
Normal file
55
src/jvmMain/java/mtmc/lang/Location.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package mtmc.lang;
|
||||
|
||||
public record Location(int index) {
|
||||
|
||||
public static int[] getLineNos(String source, int... indices) {
|
||||
int[] out = new int[indices.length];
|
||||
int index = 0, line = 1;
|
||||
while (index < source.length()) {
|
||||
for (int i = 0; i < indices.length; i++) {
|
||||
if (indices[i] == index) {
|
||||
out[i] = line;
|
||||
}
|
||||
}
|
||||
|
||||
int cp = source.charAt(index);
|
||||
if (cp == '\n') {
|
||||
line += 1;
|
||||
}
|
||||
index += Character.charCount(cp);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public LineInfo getLineInfo(String source) {
|
||||
int index = 0, lineStart = 0;
|
||||
int lineno = 1;
|
||||
int column = 1;
|
||||
while (index < source.length()) {
|
||||
if (index == this.index) {
|
||||
break;
|
||||
}
|
||||
int cp = source.charAt(index);
|
||||
|
||||
if (cp == '\n') {
|
||||
lineno += 1;
|
||||
lineStart = index + 1;
|
||||
} else {
|
||||
column += 1;
|
||||
}
|
||||
|
||||
index += Character.charCount(cp);
|
||||
}
|
||||
|
||||
while (index < source.length()) {
|
||||
int cp = source.charAt(index);
|
||||
index += Character.charCount(cp);
|
||||
if (cp == '\n') break;
|
||||
}
|
||||
String line = source.substring(lineStart, index);
|
||||
|
||||
return new LineInfo(lineno, column, line);
|
||||
}
|
||||
|
||||
public record LineInfo(int lineno, int column, String line) {}
|
||||
}
|
||||
43
src/jvmMain/java/mtmc/lang/ParseException.java
Normal file
43
src/jvmMain/java/mtmc/lang/ParseException.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package mtmc.lang;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ParseException extends Exception {
|
||||
public final List<Message> messages;
|
||||
|
||||
public ParseException(Message message, Message ...rest) {
|
||||
var messages = new ArrayList<Message>(1 + rest.length);
|
||||
messages.add(message);
|
||||
messages.addAll(Arrays.asList(rest));
|
||||
this.messages = Collections.unmodifiableList(messages);
|
||||
}
|
||||
|
||||
public ParseException(ParseException parent, Message message, Message ...rest) {
|
||||
var messages = new ArrayList<Message>( 1 + rest.length + parent.messages.size());
|
||||
messages.add(message);
|
||||
messages.addAll(Arrays.asList(rest));
|
||||
messages.addAll(parent.messages);
|
||||
this.messages = Collections.unmodifiableList(messages);
|
||||
}
|
||||
|
||||
public record Message(Span span, String message) {
|
||||
public Message(Token token, String message) {
|
||||
this(Span.of(token), message);
|
||||
}
|
||||
|
||||
public Token start() {
|
||||
return span.start();
|
||||
}
|
||||
|
||||
public Token end() {
|
||||
return span.end();
|
||||
}
|
||||
}
|
||||
|
||||
public String report(String source) {
|
||||
return "TODO: I ain't no snitch";
|
||||
}
|
||||
}
|
||||
17
src/jvmMain/java/mtmc/lang/Span.java
Normal file
17
src/jvmMain/java/mtmc/lang/Span.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package mtmc.lang;
|
||||
|
||||
public record Span(Token start, Token end) {
|
||||
|
||||
public static Span of(Token token) {
|
||||
return new Span(token, token);
|
||||
}
|
||||
|
||||
public static Span of(Token start, Token end) {
|
||||
return new Span(start, end);
|
||||
}
|
||||
|
||||
public boolean isOnSingleLine(String source) {
|
||||
int[] lines = Location.getLineNos(source, start.start(), end.end());
|
||||
return lines[0] == lines[1];
|
||||
}
|
||||
}
|
||||
15
src/jvmMain/java/mtmc/lang/Token.java
Normal file
15
src/jvmMain/java/mtmc/lang/Token.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package mtmc.lang;
|
||||
|
||||
public interface Token {
|
||||
Location getStart();
|
||||
Location getEnd();
|
||||
String getContent();
|
||||
|
||||
default int start() {
|
||||
return getStart().index();
|
||||
}
|
||||
|
||||
default int end() {
|
||||
return getEnd().index();
|
||||
}
|
||||
}
|
||||
1415
src/jvmMain/java/mtmc/lang/sea/SeaCompiler.java
Normal file
1415
src/jvmMain/java/mtmc/lang/sea/SeaCompiler.java
Normal file
File diff suppressed because it is too large
Load Diff
47
src/jvmMain/java/mtmc/lang/sea/SeaLanguage.java
Normal file
47
src/jvmMain/java/mtmc/lang/sea/SeaLanguage.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package mtmc.lang.sea;
|
||||
|
||||
import mtmc.lang.CompilationException;
|
||||
import mtmc.lang.Language;
|
||||
import mtmc.lang.ParseException;
|
||||
import mtmc.lang.sea.ast.Error;
|
||||
import mtmc.lang.sea.ast.Unit;
|
||||
import mtmc.os.exec.Executable;
|
||||
|
||||
public class SeaLanguage implements Language {
|
||||
@Override
|
||||
public Executable compileExecutable(String filename, String source) throws ParseException, CompilationException {
|
||||
var tokens = Token.tokenize(source);
|
||||
var parser = new SeaParser(filename, source, tokens);
|
||||
Unit program = parser.parseUnit();
|
||||
var errors = program.collectErrors();
|
||||
if (!errors.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Error error : errors) {
|
||||
reportError(source, sb, error.exception());
|
||||
}
|
||||
throw new RuntimeException(sb.toString());
|
||||
}
|
||||
|
||||
|
||||
var compiler = new SeaCompiler(program);
|
||||
return compiler.compile();
|
||||
}
|
||||
|
||||
private static void reportError(String src, StringBuilder sb, ParseException e) {
|
||||
sb.append("Error:\n");
|
||||
for (var msg : e.messages) {
|
||||
var lo = Token.getLineAndOffset(src, msg.start().start());
|
||||
int lineNo = lo[0];
|
||||
int column = lo[1];
|
||||
var line = Token.getLineFor(src, msg.start().start());
|
||||
String prefix = " %03d:%03d | ".formatted(lineNo, column);
|
||||
String info = " ".repeat(prefix.length() - 2) + "| ";
|
||||
sb.append(info).append(msg.message()).append('\n');
|
||||
sb.append(prefix).append(line).append('\n');
|
||||
sb
|
||||
.repeat(' ', prefix.length() + column - 1)
|
||||
.repeat('^', Math.max(1, msg.end().end() - msg.start().start()));
|
||||
sb.append("\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
1555
src/jvmMain/java/mtmc/lang/sea/SeaParser.java
Normal file
1555
src/jvmMain/java/mtmc/lang/sea/SeaParser.java
Normal file
File diff suppressed because it is too large
Load Diff
231
src/jvmMain/java/mtmc/lang/sea/SeaType.java
Normal file
231
src/jvmMain/java/mtmc/lang/sea/SeaType.java
Normal file
@@ -0,0 +1,231 @@
|
||||
package mtmc.lang.sea;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public sealed interface SeaType {
|
||||
default int size() {
|
||||
if (this == CHAR) return 2;
|
||||
if (this == INT) return 2;
|
||||
if (this == VOID) return 0;
|
||||
if (this instanceof Pointer) return 2;
|
||||
if (this instanceof Struct struct) {
|
||||
int size = 0;
|
||||
for (Map.Entry<String, SeaType> fieldSet : struct.fields.entrySet()) {
|
||||
SeaType type = fieldSet.getValue();
|
||||
size += type.size();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
throw new IllegalStateException("sizeof " + getClass().getName() + " is undefined");
|
||||
}
|
||||
|
||||
default boolean isArithmetic() {
|
||||
return this == CHAR || this == INT;
|
||||
}
|
||||
|
||||
default boolean isIntegral() {
|
||||
return this == CHAR || this == INT || this instanceof Pointer;
|
||||
}
|
||||
|
||||
default boolean isStructure() {
|
||||
return this instanceof Struct;
|
||||
}
|
||||
|
||||
default boolean isInt() {
|
||||
return this == INT;
|
||||
}
|
||||
|
||||
default boolean isChar() {
|
||||
return this == CHAR;
|
||||
}
|
||||
|
||||
default boolean isVoid() {
|
||||
return this == VOID;
|
||||
}
|
||||
|
||||
default boolean isAnIntegralPointer() {
|
||||
return this instanceof Pointer(SeaType component) && component.isIntegral();
|
||||
}
|
||||
|
||||
default boolean isAPointerToAnInt() {
|
||||
return this instanceof Pointer(SeaType component) && component.isInt();
|
||||
}
|
||||
|
||||
default boolean isAPointerTo(SeaType inner) {
|
||||
return this instanceof Pointer(SeaType it) && it.equals(inner);
|
||||
}
|
||||
|
||||
default boolean isAPointer() {
|
||||
return this instanceof Pointer;
|
||||
}
|
||||
|
||||
default boolean isFunc() {
|
||||
return this instanceof Func;
|
||||
}
|
||||
|
||||
default SeaType componentType() {
|
||||
return ((Pointer) this).component;
|
||||
}
|
||||
|
||||
default SeaType resultType() {
|
||||
return ((Func) this).result();
|
||||
}
|
||||
|
||||
default void checkConversionTo(SeaType other) throws ConversionError {
|
||||
if (this.isVoid() || other.isVoid()) throw new ConversionError(this, other, "void is not assignable to void");
|
||||
if (this.isArithmetic() && other.isArithmetic()) return;
|
||||
if (this.isAPointer() && other.isAPointer()) return;
|
||||
if (this instanceof Initializer initializer && other instanceof Struct s) {
|
||||
// this is kinda complex
|
||||
// the way this should work is we process named assignments and then based on the last
|
||||
// index of the named assignments, we start putting in values
|
||||
// the challenge here is that the blob may have too many values or may initialize them improperly
|
||||
if (initializer.values.size() != s.fields.size()) {
|
||||
throw new ConversionError(this, other, "initializer has too many or too few values");
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (Map.Entry<String, SeaType> entry : s.fields.entrySet()) {
|
||||
var name = entry.getKey();
|
||||
var ty = entry.getValue();
|
||||
var valueTy = initializer.values.get(i);
|
||||
|
||||
try {
|
||||
valueTy.checkConversionTo(ty);
|
||||
} catch (ConversionError error) {
|
||||
throw new ConversionError(ty, valueTy,
|
||||
"value cannot be assigned to " + ty.repr() + " for '" + name + "'", error);
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!this.equals(other)) {
|
||||
throw new ConversionError(this, other, this.repr() + " is not convertible to " + other.repr());
|
||||
}
|
||||
}
|
||||
|
||||
class ConversionError extends Exception {
|
||||
public final SeaType fromType, toType;
|
||||
|
||||
private ConversionError(SeaType fromType, SeaType toType, String message) {
|
||||
super(message);
|
||||
this.fromType = fromType;
|
||||
this.toType = toType;
|
||||
}
|
||||
|
||||
private ConversionError(SeaType fromType, SeaType toType, String message, ConversionError parent) {
|
||||
super(message, parent);
|
||||
this.fromType = fromType;
|
||||
this.toType = toType;
|
||||
}
|
||||
}
|
||||
|
||||
default boolean isCastableTo(SeaType target) {
|
||||
if (target.isVoid()) return true;
|
||||
if (this.isAPointer() && target.isInt()) return true;
|
||||
if (this.isArithmetic() && target.isArithmetic()) return true;
|
||||
return this.equals(target);
|
||||
}
|
||||
|
||||
default String repr() {
|
||||
if (this instanceof Pointer p) {
|
||||
if (p.baseType() instanceof Func(List<SeaType> params, boolean isVararg, SeaType result)) {
|
||||
var s = new StringBuilder();
|
||||
s.append(result.repr()).append("(*");
|
||||
var x = p.component;
|
||||
while (x instanceof Pointer p2) {
|
||||
x = p2.component;
|
||||
s.append("*");
|
||||
}
|
||||
s.append(")(");
|
||||
int i = 0;
|
||||
for (var param : params) {
|
||||
if (i > 0) s.append(", ");
|
||||
s.append(param.repr());
|
||||
i = i + 1;
|
||||
}
|
||||
s.append(")");
|
||||
return s.toString();
|
||||
} else {
|
||||
return p.component.repr() + "*";
|
||||
}
|
||||
}
|
||||
if (this == CHAR) return "char";
|
||||
if (this == INT) return "int";
|
||||
if (this == VOID) return "void";
|
||||
if (this instanceof Func(List<SeaType> params, boolean isVararg, SeaType result)) {
|
||||
var s = new StringBuilder();
|
||||
s.append(result.repr());
|
||||
s.append("(");
|
||||
int i = 0;
|
||||
for (var param : params) {
|
||||
if (i > 0) s.append(", ");
|
||||
s.append(param.repr());
|
||||
i = i + 1;
|
||||
}
|
||||
s.append(")");
|
||||
return s.toString();
|
||||
}
|
||||
if (this instanceof Initializer(List<SeaType> values)) {
|
||||
var s = new StringBuilder();
|
||||
s.append("{");
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
if (i > 0) s.append(", ");
|
||||
s.append(values.get(i).repr());
|
||||
}
|
||||
s.append("}");
|
||||
return s.toString();
|
||||
}
|
||||
if (this instanceof Struct s) {
|
||||
return "struct " + s.name;
|
||||
}
|
||||
throw new UnsupportedOperationException("unknown type " + this);
|
||||
}
|
||||
|
||||
SeaType CHAR = new Primitive("char");
|
||||
SeaType INT = new Primitive("int");
|
||||
SeaType VOID = new Primitive("void");
|
||||
|
||||
record Pointer(SeaType component) implements SeaType {
|
||||
SeaType baseType() {
|
||||
var ty = component;
|
||||
while (ty instanceof Pointer(SeaType c)) {
|
||||
ty = c;
|
||||
}
|
||||
return ty;
|
||||
}
|
||||
}
|
||||
|
||||
final class Primitive implements SeaType {
|
||||
// this is purely for debug info lmfao
|
||||
public final String name;
|
||||
|
||||
private Primitive(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
record Func(List<SeaType> params, boolean isVararg, SeaType result) implements SeaType {
|
||||
public Func(List<SeaType> params, SeaType result) {
|
||||
this(params, false, result);
|
||||
}
|
||||
}
|
||||
|
||||
record Struct(String name, LinkedHashMap<String, SeaType> fields) implements SeaType {
|
||||
public SeaType field(String name) {
|
||||
return fields.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
record Initializer(List<SeaType> values) implements SeaType {
|
||||
}
|
||||
}
|
||||
59
src/jvmMain/java/mtmc/lang/sea/Symbol.java
Normal file
59
src/jvmMain/java/mtmc/lang/sea/Symbol.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package mtmc.lang.sea;
|
||||
|
||||
import mtmc.lang.sea.ast.DeclarationFunc;
|
||||
import mtmc.lang.sea.ast.DeclarationVar;
|
||||
import mtmc.lang.sea.ast.StatementVar;
|
||||
import mtmc.lang.sea.ast.TypeDeclaration;
|
||||
|
||||
public class Symbol {
|
||||
public final String name;
|
||||
public final SeaType type;
|
||||
public final TypeDeclaration typeDecl;
|
||||
public final boolean isParam, isGlobal;
|
||||
|
||||
public Symbol(DeclarationFunc.Param param) {
|
||||
this.name = param.name.content();
|
||||
this.type = param.type.type();
|
||||
this.typeDecl = null;
|
||||
this.isParam = true;
|
||||
this.isGlobal = false;
|
||||
}
|
||||
|
||||
public Symbol(DeclarationVar decl) {
|
||||
this.name = decl.name();
|
||||
this.type = decl.type.type();
|
||||
this.typeDecl = null;
|
||||
this.isParam = false;
|
||||
this.isGlobal = true;
|
||||
}
|
||||
|
||||
public Symbol(StatementVar stmt) {
|
||||
this.name = stmt.name();
|
||||
this.type = stmt.type.type();
|
||||
this.typeDecl = null;
|
||||
this.isParam = false;
|
||||
this.isGlobal = false;
|
||||
}
|
||||
|
||||
public Symbol(DeclarationFunc func) {
|
||||
this.name = func.name.content();
|
||||
this.type = func.type();
|
||||
this.typeDecl = null;
|
||||
this.isParam = false;
|
||||
this.isGlobal = true;
|
||||
}
|
||||
|
||||
public Symbol(TypeDeclaration declaration) {
|
||||
this.name = declaration.name();
|
||||
this.type = null;
|
||||
this.typeDecl = declaration;
|
||||
this.isParam = false;
|
||||
this.isGlobal = false;
|
||||
}
|
||||
|
||||
public boolean isAddressable() {
|
||||
if (this.typeDecl != null) throw new IllegalStateException("cannot address non-data symbol");
|
||||
if (this.isParam) return false; // parameters are not addressable!
|
||||
return true;
|
||||
}
|
||||
}
|
||||
426
src/jvmMain/java/mtmc/lang/sea/Token.java
Normal file
426
src/jvmMain/java/mtmc/lang/sea/Token.java
Normal file
@@ -0,0 +1,426 @@
|
||||
package mtmc.lang.sea;
|
||||
|
||||
import mtmc.lang.Location;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public record Token(
|
||||
Type type,
|
||||
@NotNull
|
||||
String content,
|
||||
int start,
|
||||
int end
|
||||
) implements mtmc.lang.Token {
|
||||
public static final Token SOF = new Token(Type.SOF, "", 0, 0);
|
||||
public static final Token EOF = new Token(Type.EOF, "", Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
|
||||
public enum Type {
|
||||
// Special
|
||||
LIT_INT(null),
|
||||
LIT_STR(null),
|
||||
LIT_CHAR(null),
|
||||
LIT_IDENT(null),
|
||||
KW_TYPEDEF("typedef"),
|
||||
KW_STRUCT("struct"),
|
||||
KW_IF("if"),
|
||||
KW_ELSE("else"),
|
||||
KW_FOR("for"),
|
||||
KW_WHILE("while"),
|
||||
KW_DO("do"),
|
||||
KW_GOTO("goto"),
|
||||
KW_CONTINUE("continue"),
|
||||
KW_BREAK("break"),
|
||||
KW_RETURN("return"),
|
||||
KW_SIZEOF("sizeof"),
|
||||
KW_INT("int"),
|
||||
KW_CHAR("char"),
|
||||
KW_VOID("void"),
|
||||
SOF(null),
|
||||
EOF(null),
|
||||
|
||||
// Groups
|
||||
LEFT_PAREN("("),
|
||||
RIGHT_PAREN(")"),
|
||||
LEFT_BRACKET("["),
|
||||
RIGHT_BRACKET("]"),
|
||||
LEFT_BRACE("{"),
|
||||
RIGHT_BRACE("}"),
|
||||
|
||||
// Simple Punct
|
||||
DOT3("..."),
|
||||
DOT("."),
|
||||
SEMICOLON(";"),
|
||||
COMMA(","),
|
||||
COLON(":"),
|
||||
TILDE("~"),
|
||||
QUESTION("?"),
|
||||
|
||||
PLUS2("++"),
|
||||
PLUS_EQ("+="),
|
||||
PLUS("+"),
|
||||
|
||||
DASH2("--"),
|
||||
DASH_EQ("-="),
|
||||
ARROW("->"),
|
||||
DASH("-"),
|
||||
|
||||
STAR_EQ("*="),
|
||||
STAR("*"),
|
||||
|
||||
SLASH_EQ("/="),
|
||||
SLASH("/"),
|
||||
|
||||
PERCENT_EQ("%="),
|
||||
PERCENT("%"),
|
||||
|
||||
AMPERSAND2("&&"),
|
||||
AMPERSAND_EQ("&="),
|
||||
AMPERSAND("&"),
|
||||
|
||||
BAR2("||"),
|
||||
BAR_EQ("|="),
|
||||
BAR("|"),
|
||||
|
||||
CARET("^"),
|
||||
CARET_EQ("^="),
|
||||
|
||||
LEFT_ARROW2_EQ("<<="),
|
||||
LEFT_ARROW2("<<"),
|
||||
LEFT_ARROW_EQ("<="),
|
||||
LEFT_ARROW("<"),
|
||||
|
||||
RIGHT_ARROW2_EQ(">>="),
|
||||
RIGHT_ARROW2(">>"),
|
||||
RIGHT_ARROW_EQ(">="),
|
||||
RIGHT_ARROW(">"),
|
||||
|
||||
EQUAL2("=="),
|
||||
EQUAL("="),
|
||||
|
||||
BANG_EQ("!="),
|
||||
BANG("!");
|
||||
|
||||
public final String lex;
|
||||
|
||||
public static final Type[] PUNCT;
|
||||
static {
|
||||
List<Type> list = new ArrayList<>();
|
||||
for (Type t : Type.values()) {
|
||||
if (t.lex != null) {
|
||||
list.add(t);
|
||||
}
|
||||
}
|
||||
PUNCT = list.toArray(new Type[0]);
|
||||
}
|
||||
|
||||
public static final Type[] KEYWORDS;
|
||||
static {
|
||||
List<Type> list = new ArrayList<>();
|
||||
for (Type t : Type.values()) {
|
||||
if (t.name().startsWith("KW_")) {
|
||||
list.add(t);
|
||||
}
|
||||
}
|
||||
KEYWORDS = list.toArray(new Type[0]);
|
||||
}
|
||||
|
||||
Type(String lex) {
|
||||
this.lex = lex;
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] getLineAndOffset(String src, int index) {
|
||||
int line = 1;
|
||||
int column = 1;
|
||||
for (int i = 0; i < index && i < src.length(); i++) {
|
||||
char c = src.charAt(i);
|
||||
if (c == '\n') {
|
||||
line = line + 1;
|
||||
column = 1;
|
||||
} else {
|
||||
column = column + 1;
|
||||
}
|
||||
}
|
||||
return new int[]{line, column};
|
||||
}
|
||||
|
||||
public static String getLineFor(String src, int index) {
|
||||
int start = 0;
|
||||
for (int i = Math.min(index, src.length() - 1); i >= 0; i--) {
|
||||
if (src.charAt(i) == '\n') {
|
||||
start = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int end = src.length();
|
||||
for (int i = index; i < src.length(); i++) {
|
||||
if (src.charAt(i) == '\n') {
|
||||
break;
|
||||
}
|
||||
end = i + 1;
|
||||
}
|
||||
return src.substring(start, end);
|
||||
}
|
||||
|
||||
public static String highlight(String src, int start, int end) {
|
||||
var s = getLineAndOffset(src, start);
|
||||
var e = getLineAndOffset(src, end);
|
||||
|
||||
int lineStart;
|
||||
if (s[0] != e[0]) {
|
||||
lineStart = 0;
|
||||
} else {
|
||||
lineStart = s[1] - 1;
|
||||
}
|
||||
|
||||
int lineEnd = e[1] - 1;
|
||||
|
||||
String line = getLineFor(src, end);
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
int off = 0;
|
||||
|
||||
if (lineStart > 10) {
|
||||
result.append("... ");
|
||||
off += 4;
|
||||
result.append(line.substring(lineStart, lineEnd));
|
||||
} else {
|
||||
result.append(line.substring(0, lineEnd));
|
||||
}
|
||||
|
||||
result.append('\n');
|
||||
result.repeat(' ', off + lineStart);
|
||||
if (start == Integer.MAX_VALUE) {
|
||||
result.append("^ (at EOL)");
|
||||
} else {
|
||||
result.repeat('^', lineEnd - lineStart);
|
||||
result.append(" (here)");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static List<Token> tokenize(String src) throws TokenizeException {
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
int offset = 0;
|
||||
do {
|
||||
Token token = tokenizeOne(src, offset);
|
||||
if (token == null) break;
|
||||
tokens.add(token);
|
||||
offset = token.end();
|
||||
} while (true);
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private static boolean match(String str, int start, String token) {
|
||||
if (str == null) return false;
|
||||
if (str.length() - start < token.length()) return false;
|
||||
for (int i = 0; i < token.length(); i++) {
|
||||
char c = str.charAt(start + i);
|
||||
char d = token.charAt(i);
|
||||
if (c != d) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean match(String str, int start, char c) {
|
||||
if (str == null) return false;
|
||||
if (str.length() - start < Character.charCount(c)) return false;
|
||||
return str.charAt(start) == c;
|
||||
}
|
||||
|
||||
public static Token tokenizeOne(String src, int offset) throws TokenizeException {
|
||||
while (offset < src.length()) {
|
||||
if (Character.isWhitespace(src.charAt(offset))) {
|
||||
offset += Character.charCount(src.charAt(offset));
|
||||
} else if (match(src, offset, "//")) {
|
||||
offset += 2;
|
||||
while (offset < src.length()) {
|
||||
char c = src.charAt(offset);
|
||||
offset += Character.charCount(c);
|
||||
if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (match(src, offset, "/*")) {
|
||||
offset += 2;
|
||||
while (offset < src.length()) {
|
||||
if (match(src, offset, "*/")) {
|
||||
offset += 2;
|
||||
break;
|
||||
} else {
|
||||
offset += Character.charCount(src.charAt(offset));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (offset >= src.length()) return null;
|
||||
|
||||
int start = offset;
|
||||
Type type;
|
||||
String content = null;
|
||||
|
||||
char c = src.charAt(offset);
|
||||
if (Character.isDigit(c)) {
|
||||
do {
|
||||
offset += Character.charCount(src.charAt(offset));
|
||||
} while (offset < src.length() && Character.isDigit(src.charAt(offset)));
|
||||
content = src.substring(start, offset);
|
||||
type = Type.LIT_INT;
|
||||
} else if (Character.isLetter(c) || c == '_') {
|
||||
do {
|
||||
offset += Character.charCount(src.charAt(offset));
|
||||
} while (offset < src.length() && (Character.isLetter(src.charAt(offset)) || Character.isDigit(src.charAt(offset)) || src.charAt(offset) == '_'));
|
||||
content = src.substring(start, offset);
|
||||
type = Type.LIT_IDENT;
|
||||
for (var ty : Type.KEYWORDS) {
|
||||
if (content.equals(ty.lex)) {
|
||||
type = ty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (c == '\'') {
|
||||
offset += Character.charCount(c);
|
||||
char d = src.charAt(offset);
|
||||
offset += Character.charCount(d);
|
||||
if (d == '\\') {
|
||||
if (offset >= src.length()) throw new TokenizeException("invalid character escape " + d, start, offset);
|
||||
d = src.charAt(offset);
|
||||
offset += Character.charCount(d);
|
||||
content = switch (d) {
|
||||
case 'n':
|
||||
yield "\n";
|
||||
case 'r':
|
||||
yield "\r";
|
||||
case 't':
|
||||
yield "\t";
|
||||
case '\\':
|
||||
yield "\\";
|
||||
case '\'':
|
||||
yield "'";
|
||||
case '"':
|
||||
yield "\"";
|
||||
case '?':
|
||||
yield "?";
|
||||
default:
|
||||
throw new TokenizeException("invalid character escape " + d, start, offset);
|
||||
};
|
||||
} else {
|
||||
content = String.valueOf(d);
|
||||
}
|
||||
|
||||
if (offset >= src.length() || src.charAt(offset) != '\'') {
|
||||
throw new TokenizeException("unterminated character literal", start, offset);
|
||||
}
|
||||
offset += Character.charCount('\'');
|
||||
type = Type.LIT_CHAR;
|
||||
} else if (c == '"') {
|
||||
offset += Character.charCount(src.charAt(offset));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (offset < src.length() && src.charAt(offset) != '"') {
|
||||
char d = src.charAt(offset);
|
||||
offset += Character.charCount(d);
|
||||
|
||||
if (d == '\\') {
|
||||
d = src.charAt(offset);
|
||||
offset += Character.charCount(d);
|
||||
char s = switch (d) {
|
||||
case 'n':
|
||||
yield '\n';
|
||||
case 'r':
|
||||
yield '\r';
|
||||
case 't':
|
||||
yield '\t';
|
||||
case '\\':
|
||||
yield '\\';
|
||||
case '\'':
|
||||
yield '\'';
|
||||
case '"':
|
||||
yield '"';
|
||||
case '?':
|
||||
yield '?';
|
||||
default:
|
||||
throw new TokenizeException("invalid string escape " + d, start, offset);
|
||||
};
|
||||
sb.append(s);
|
||||
} else if (d == '\n') {
|
||||
break;
|
||||
} else {
|
||||
sb.append(d);
|
||||
}
|
||||
}
|
||||
|
||||
if (offset >= src.length() || src.charAt(offset) != '"') {
|
||||
throw new TokenizeException("unterminated string literal", start, offset);
|
||||
}
|
||||
|
||||
content = sb.toString();
|
||||
offset += Character.charCount('\"');
|
||||
type = Type.LIT_STR;
|
||||
} else {
|
||||
type = null;
|
||||
for (Type t : Type.PUNCT) {
|
||||
if (match(src, start, t.lex)) {
|
||||
type = t;
|
||||
content = t.lex;
|
||||
offset += t.lex.length();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
throw new TokenizeException("unexpected character '" + src.charAt(start) + "'", start, offset);
|
||||
}
|
||||
}
|
||||
|
||||
Objects.requireNonNull(content);
|
||||
return new Token(type, content, start, offset);
|
||||
}
|
||||
|
||||
public static class TokenizeException extends IllegalArgumentException {
|
||||
public final int start, end;
|
||||
|
||||
public TokenizeException(String msg, int start, int end) {
|
||||
super(msg);
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TokenizeException at " + start + ":" + end + ", " + getLocalizedMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof String s) return Objects.equals(content, s);
|
||||
if (!(o instanceof Token token)) return false;
|
||||
return end == token.end && start == token.start && Objects.equals(content, token.content) && type == token.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, content, start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getStart() {
|
||||
return new Location(start);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getEnd() {
|
||||
return new Location(end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContent() {
|
||||
return content();
|
||||
}
|
||||
}
|
||||
139
src/jvmMain/java/mtmc/lang/sea/ast/Ast.java
Normal file
139
src/jvmMain/java/mtmc/lang/sea/ast/Ast.java
Normal file
@@ -0,0 +1,139 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.Span;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public sealed abstract class Ast permits Declaration, DeclarationFunc.Param, DeclarationStruct.Field, Expression, Statement, TypeExpr, Unit {
|
||||
public final Token start, end;
|
||||
|
||||
public Ast(Token start, Token end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public Span span() {
|
||||
return Span.of(start, end);
|
||||
}
|
||||
|
||||
public Stream<Ast> getChildren() {
|
||||
return switch (this) {
|
||||
case DeclarationFunc declarationFunc -> {
|
||||
Stream<Ast> out = Stream.of(declarationFunc.returnType);
|
||||
out = Stream.concat(out, declarationFunc.params.params().stream());
|
||||
if (declarationFunc.body != null) {
|
||||
out = Stream.concat(out, Stream.of(declarationFunc.body));
|
||||
}
|
||||
yield out;
|
||||
}
|
||||
case DeclarationSyntaxError ignored -> Stream.empty();
|
||||
case DeclarationTypedef declarationTypedef -> Stream.of(declarationTypedef.type);
|
||||
case DeclarationVar declarationVar -> {
|
||||
Stream<Ast> out = Stream.of(declarationVar.type);
|
||||
if (declarationVar.initializer != null) {
|
||||
out = Stream.concat(out, Stream.of(declarationVar.initializer));
|
||||
}
|
||||
yield out;
|
||||
}
|
||||
case DeclarationStruct struct -> struct.fields.stream().map(x -> x);
|
||||
case DeclarationStruct.Field field -> Stream.of(field.type);
|
||||
case DeclarationFunc.Param param -> Stream.of(param.type);
|
||||
case ExpressionAccess expressionAccess -> Stream.of(expressionAccess.value);
|
||||
case ExpressionBin expressionBin -> Stream.of(expressionBin.lhs, expressionBin.rhs);
|
||||
case ExpressionCall expressionCall -> {
|
||||
Stream<Ast> out = Stream.of(expressionCall.functor);
|
||||
out = Stream.concat(out, expressionCall.args.stream());
|
||||
yield out;
|
||||
}
|
||||
case ExpressionInitializer init -> init.values.stream().map(x -> x);
|
||||
case ExpressionCast expressionCast -> Stream.of(expressionCast.type, expressionCast.value);
|
||||
case ExpressionChar ignored -> Stream.empty();
|
||||
case ExpressionIdent ignored -> Stream.empty();
|
||||
case ExpressionIndex expressionIndex -> Stream.of(expressionIndex.array, expressionIndex.index);
|
||||
case ExpressionInteger ignored -> Stream.empty();
|
||||
case ExpressionParens expressionParens -> Stream.of(expressionParens.inner);
|
||||
case ExpressionPostfix expressionPostfix -> Stream.of(expressionPostfix.inner);
|
||||
case ExpressionPrefix expressionPrefix -> Stream.of(expressionPrefix.inner);
|
||||
case ExpressionString ignored -> Stream.empty();
|
||||
case ExpressionTypeError typeError -> Stream.of(typeError.inner);
|
||||
case ExpressionSyntaxError expressionSyntaxError -> {
|
||||
if (expressionSyntaxError.child != null) {
|
||||
yield Stream.of(expressionSyntaxError.child);
|
||||
} else {
|
||||
yield Stream.empty();
|
||||
}
|
||||
}
|
||||
case ExpressionTernary expressionTernary -> Stream.of(
|
||||
expressionTernary.cond,
|
||||
expressionTernary.then,
|
||||
expressionTernary.otherwise
|
||||
);
|
||||
case StatementBlock statementBlock -> statementBlock.statements.stream().map(x -> x);
|
||||
case StatementBreak ignored -> Stream.empty();
|
||||
case StatementContinue ignored -> Stream.empty();
|
||||
case StatementDoWhile statementDoWhile -> Stream.of(statementDoWhile.body, statementDoWhile.condition);
|
||||
case StatementExpression statementExpression -> Stream.of(statementExpression.expression);
|
||||
case StatementFor statementFor -> {
|
||||
Stream<Ast> out = Stream.empty();
|
||||
if (statementFor.initExpression != null) {
|
||||
out = Stream.concat(out, Stream.of(statementFor.initExpression));
|
||||
} else if (statementFor.initStatement != null) {
|
||||
out = Stream.concat(out, Stream.of(statementFor.initStatement));
|
||||
}
|
||||
if (statementFor.condition != null) {
|
||||
out = Stream.concat(out, Stream.of(statementFor.condition));
|
||||
}
|
||||
if (statementFor.inc != null) {
|
||||
out = Stream.concat(out, Stream.of(statementFor.inc));
|
||||
}
|
||||
out = Stream.concat(out, Stream.of(statementFor.body));
|
||||
yield out;
|
||||
}
|
||||
case StatementGoto ignored -> Stream.empty();
|
||||
case StatementIf statementIf -> {
|
||||
Stream<Ast> out = Stream.of(statementIf.condition, statementIf.body);
|
||||
if (statementIf.elseBody != null) out = Stream.concat(out, Stream.of(statementIf.elseBody));
|
||||
yield out;
|
||||
}
|
||||
case StatementReturn statementReturn -> {
|
||||
if (statementReturn.value == null) {
|
||||
yield Stream.empty();
|
||||
} else {
|
||||
yield Stream.of(statementReturn.value);
|
||||
}
|
||||
}
|
||||
case StatementSyntaxError ignored -> Stream.empty();
|
||||
case StatementVar statementVar -> {
|
||||
Stream<Ast> out = Stream.of(statementVar.type);
|
||||
if (statementVar.initValue != null) {
|
||||
out = Stream.concat(out, Stream.of(statementVar.initValue));
|
||||
}
|
||||
yield out;
|
||||
}
|
||||
case StatementWhile statementWhile -> Stream.of(statementWhile.condition, statementWhile.body);
|
||||
case TypeExprArray typeExprArray -> Stream.of(typeExprArray.inner);
|
||||
case TypeExprChar ignored -> Stream.empty();
|
||||
case TypeExprInt ignored -> Stream.empty();
|
||||
case TypeExprRef ignored -> Stream.empty();
|
||||
case TypeExprVoid ignored -> Stream.empty();
|
||||
case TypePointer ignored -> Stream.empty();
|
||||
case Unit unit -> unit.declarations.stream().map(x -> x);
|
||||
};
|
||||
}
|
||||
|
||||
public List<Error> collectErrors() {
|
||||
var errors = new ArrayList<Error>();
|
||||
collectErrors(errors);
|
||||
return errors;
|
||||
}
|
||||
|
||||
public void collectErrors(List<Error> errors) {
|
||||
if (this instanceof Error e) {
|
||||
errors.add(e);
|
||||
}
|
||||
getChildren().forEach(child -> child.collectErrors(errors));
|
||||
}
|
||||
}
|
||||
9
src/jvmMain/java/mtmc/lang/sea/ast/Declaration.java
Normal file
9
src/jvmMain/java/mtmc/lang/sea/ast/Declaration.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public abstract sealed class Declaration extends Ast permits DeclarationFunc, DeclarationStruct, DeclarationSyntaxError, DeclarationTypedef, DeclarationVar {
|
||||
public Declaration(Token start, Token end) {
|
||||
super(start, end);
|
||||
}
|
||||
}
|
||||
59
src/jvmMain/java/mtmc/lang/sea/ast/DeclarationFunc.java
Normal file
59
src/jvmMain/java/mtmc/lang/sea/ast/DeclarationFunc.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class DeclarationFunc extends Declaration {
|
||||
public final TypeExpr returnType;
|
||||
public final Token name;
|
||||
public final ParamList params;
|
||||
public final StatementBlock body;
|
||||
|
||||
public DeclarationFunc(TypeExpr returnType, Token name, ParamList paramList, StatementBlock body, Token end) {
|
||||
super(returnType.start, end);
|
||||
this.returnType = returnType;
|
||||
this.name = name;
|
||||
this.params = paramList;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public static final class Param extends Ast {
|
||||
public final TypeExpr type;
|
||||
public final Token name;
|
||||
|
||||
public Param(TypeExpr type, Token name) {
|
||||
super(type.start, name.end() < type.end.end() ? type.end : name);
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
private SeaType.Func type;
|
||||
public SeaType.Func type() {
|
||||
if (type == null) {
|
||||
var paramTypes = new ArrayList<SeaType>(params.size());
|
||||
for (Param param : params.params) {
|
||||
paramTypes.add(param.type.type());
|
||||
}
|
||||
type = new SeaType.Func(
|
||||
paramTypes,
|
||||
params.isVararg,
|
||||
returnType.type()
|
||||
);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public record ParamList(List<Param> params, boolean isVararg) {
|
||||
public int size() {
|
||||
return params.size();
|
||||
}
|
||||
|
||||
public SeaType getParamType(int i) {
|
||||
return params.get(i).type.type();
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/jvmMain/java/mtmc/lang/sea/ast/DeclarationStruct.java
Normal file
54
src/jvmMain/java/mtmc/lang/sea/ast/DeclarationStruct.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
public final class DeclarationStruct extends Declaration implements TypeDeclaration {
|
||||
public final Token name;
|
||||
public final List<Field> fields;
|
||||
|
||||
public DeclarationStruct(Token start, Token name, List<Field> fields, Token end) {
|
||||
super(start, end);
|
||||
this.name = name;
|
||||
this.fields = List.copyOf(fields);
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name.content();
|
||||
}
|
||||
|
||||
private SeaType type;
|
||||
@Override
|
||||
public SeaType type() {
|
||||
if (type == null) {
|
||||
var fields = new LinkedHashMap<String, SeaType>();
|
||||
for (var field : this.fields) {
|
||||
fields.put(field.name(), field.type());
|
||||
}
|
||||
type = new SeaType.Struct(name(), fields);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public static final class Field extends Ast {
|
||||
public final TypeExpr type;
|
||||
public final Token name;
|
||||
|
||||
public Field(TypeExpr type, Token name) {
|
||||
super(type.start, name);
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name.content();
|
||||
}
|
||||
|
||||
public SeaType type() {
|
||||
return type.type();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.ParseException;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class DeclarationSyntaxError extends Declaration implements SyntaxError {
|
||||
public final ParseException exception;
|
||||
|
||||
public DeclarationSyntaxError(Token token, ParseException parseException) {
|
||||
super(token, token);
|
||||
this.exception = parseException;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParseException exception() {
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
26
src/jvmMain/java/mtmc/lang/sea/ast/DeclarationTypedef.java
Normal file
26
src/jvmMain/java/mtmc/lang/sea/ast/DeclarationTypedef.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class DeclarationTypedef extends Declaration implements TypeDeclaration {
|
||||
public final TypeExpr type;
|
||||
public final Token name;
|
||||
|
||||
|
||||
public DeclarationTypedef(Token start, TypeExpr type, Token name, Token end) {
|
||||
super(start, type.end);
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return name.content();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeaType type() {
|
||||
return type.type();
|
||||
}
|
||||
}
|
||||
20
src/jvmMain/java/mtmc/lang/sea/ast/DeclarationVar.java
Normal file
20
src/jvmMain/java/mtmc/lang/sea/ast/DeclarationVar.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class DeclarationVar extends Declaration {
|
||||
public final TypeExpr type;
|
||||
public final Token name;
|
||||
public final Expression initializer;
|
||||
|
||||
public DeclarationVar(TypeExpr type, Token name, Expression initializer) {
|
||||
super(type.start, initializer == null ? name : initializer.end);
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.initializer = initializer;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return this.name.content();
|
||||
}
|
||||
}
|
||||
7
src/jvmMain/java/mtmc/lang/sea/ast/Error.java
Normal file
7
src/jvmMain/java/mtmc/lang/sea/ast/Error.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.ParseException;
|
||||
|
||||
public interface Error {
|
||||
ParseException exception();
|
||||
}
|
||||
23
src/jvmMain/java/mtmc/lang/sea/ast/Expression.java
Normal file
23
src/jvmMain/java/mtmc/lang/sea/ast/Expression.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public sealed abstract class Expression extends Ast permits ExpressionAccess, ExpressionBin, ExpressionCall, ExpressionCast, ExpressionChar, ExpressionIdent, ExpressionIndex, ExpressionInitializer, ExpressionInteger, ExpressionParens, ExpressionPostfix, ExpressionPrefix, ExpressionString, ExpressionSyntaxError, ExpressionTernary, ExpressionTypeError {
|
||||
private final SeaType type;
|
||||
public Expression(Token start, Token end, SeaType type) {
|
||||
super(start, end);
|
||||
this.type = Objects.requireNonNull(type, "'type' cannot be null");
|
||||
}
|
||||
|
||||
public SeaType type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public enum ValueKind {
|
||||
Addressable,
|
||||
Immediate
|
||||
}
|
||||
}
|
||||
17
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionAccess.java
Normal file
17
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionAccess.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class ExpressionAccess extends Expression {
|
||||
public final Expression value;
|
||||
public final Token access;
|
||||
public final Token prop;
|
||||
|
||||
public ExpressionAccess(Expression value, Token access, Token prop, SeaType type) {
|
||||
super(value.start, prop, type);
|
||||
this.value = value;
|
||||
this.access = access;
|
||||
this.prop = prop;
|
||||
}
|
||||
}
|
||||
21
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionBin.java
Normal file
21
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionBin.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class ExpressionBin extends Expression {
|
||||
public final Expression lhs;
|
||||
public final Token op;
|
||||
public final Expression rhs;
|
||||
|
||||
public ExpressionBin(Expression lhs, Token op, Expression rhs, SeaType type) {
|
||||
super(lhs.start, rhs.end, type);
|
||||
this.lhs = lhs;
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
|
||||
public String op() {
|
||||
return op.content();
|
||||
}
|
||||
}
|
||||
17
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionCall.java
Normal file
17
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionCall.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class ExpressionCall extends Expression {
|
||||
public final Expression functor;
|
||||
public final List<Expression> args;
|
||||
|
||||
public ExpressionCall(Expression functor, List<Expression> args, Token end, SeaType type) {
|
||||
super(functor.start, end, type);
|
||||
this.functor = functor;
|
||||
this.args = args;
|
||||
}
|
||||
}
|
||||
14
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionCast.java
Normal file
14
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionCast.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class ExpressionCast extends Expression {
|
||||
public final TypeExpr type;
|
||||
public final Expression value;
|
||||
|
||||
public ExpressionCast(Token start, TypeExpr type, Expression value) {
|
||||
super(start, value.end, type.type());
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
14
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionChar.java
Normal file
14
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionChar.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class ExpressionChar extends Expression {
|
||||
public ExpressionChar(Token token) {
|
||||
super(token, token, SeaType.CHAR);
|
||||
}
|
||||
|
||||
public Character content() {
|
||||
return start.content().charAt(0);
|
||||
}
|
||||
}
|
||||
17
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionIdent.java
Normal file
17
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionIdent.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class ExpressionIdent extends Expression {
|
||||
public final boolean isAddressable;
|
||||
|
||||
public ExpressionIdent(Token token, SeaType type, boolean isAddressable) {
|
||||
super(token, token, type);
|
||||
this.isAddressable = isAddressable;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return start.content();
|
||||
}
|
||||
}
|
||||
14
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionIndex.java
Normal file
14
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionIndex.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class ExpressionIndex extends Expression {
|
||||
public final Expression array, index;
|
||||
|
||||
public ExpressionIndex(Expression array, Expression index, Token end, SeaType type) {
|
||||
super(array.start, end, type);
|
||||
this.array = array;
|
||||
this.index = index;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class ExpressionInitializer extends Expression {
|
||||
public final List<Expression> values;
|
||||
|
||||
private static SeaType.Initializer blobType(List<Expression> values) {
|
||||
var types = new ArrayList<SeaType>();
|
||||
|
||||
for (var value : values) {
|
||||
types.add(value.type());
|
||||
}
|
||||
|
||||
return new SeaType.Initializer(types);
|
||||
}
|
||||
|
||||
public ExpressionInitializer(Token start, List<Expression> values, Token end) {
|
||||
super(start, end, blobType(values));
|
||||
this.values = List.copyOf(values);
|
||||
}
|
||||
|
||||
}
|
||||
13
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionInteger.java
Normal file
13
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionInteger.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class ExpressionInteger extends Expression {
|
||||
public final int value;
|
||||
|
||||
public ExpressionInteger(Token start) {
|
||||
super(start, start, SeaType.INT);
|
||||
this.value = Integer.parseInt(start.content());
|
||||
}
|
||||
}
|
||||
12
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionParens.java
Normal file
12
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionParens.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class ExpressionParens extends Expression {
|
||||
public final Expression inner;
|
||||
|
||||
public ExpressionParens(Token start, Expression inner, Token end) {
|
||||
super(start, end, inner.type());
|
||||
this.inner = inner;
|
||||
}
|
||||
}
|
||||
17
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionPostfix.java
Normal file
17
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionPostfix.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class ExpressionPostfix extends Expression {
|
||||
public Expression inner;
|
||||
|
||||
public ExpressionPostfix(Expression lhs, Token op, SeaType type) {
|
||||
super(lhs.start, op, type);
|
||||
this.inner = lhs;
|
||||
}
|
||||
|
||||
public String op() {
|
||||
return end.content();
|
||||
}
|
||||
}
|
||||
17
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionPrefix.java
Normal file
17
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionPrefix.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class ExpressionPrefix extends Expression {
|
||||
public final Expression inner;
|
||||
|
||||
public ExpressionPrefix(Token operator, Expression rhs, SeaType type) {
|
||||
super(operator, rhs.end, type);
|
||||
this.inner = rhs;
|
||||
}
|
||||
|
||||
public String op() {
|
||||
return start.content();
|
||||
}
|
||||
}
|
||||
18
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionString.java
Normal file
18
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionString.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class ExpressionString extends Expression {
|
||||
public ExpressionString(Token token) {
|
||||
super(token, token, new SeaType.Pointer(SeaType.CHAR));
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return start.content().getBytes();
|
||||
}
|
||||
|
||||
public String content() {
|
||||
return start.content();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.ParseException;
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public final class ExpressionSyntaxError extends Expression implements SyntaxError {
|
||||
@Nullable
|
||||
public final Expression child;
|
||||
public final ParseException exception;
|
||||
|
||||
public ExpressionSyntaxError(Token token, String message) {
|
||||
this(null, token, message);
|
||||
}
|
||||
|
||||
public ExpressionSyntaxError(@Nullable Expression child, Token token, String message) {
|
||||
super(child == null ? token : child.start, token, SeaType.INT);
|
||||
this.child = child;
|
||||
this.exception = new ParseException(new ParseException.Message(token, message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParseException exception() {
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
16
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionTernary.java
Normal file
16
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionTernary.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
|
||||
public final class ExpressionTernary extends Expression {
|
||||
public final Expression cond;
|
||||
public final Expression then;
|
||||
public final Expression otherwise;
|
||||
|
||||
public ExpressionTernary(Expression cond, Expression then, Expression otherwise, SeaType type) {
|
||||
super(cond.start, otherwise.end, type);
|
||||
this.cond = cond;
|
||||
this.then = then;
|
||||
this.otherwise = otherwise;
|
||||
}
|
||||
}
|
||||
20
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionTypeError.java
Normal file
20
src/jvmMain/java/mtmc/lang/sea/ast/ExpressionTypeError.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.ParseException;
|
||||
|
||||
public final class ExpressionTypeError extends Expression implements Error {
|
||||
public final Expression inner;
|
||||
public final ParseException exception;
|
||||
|
||||
public ExpressionTypeError(Expression inner, String message) {
|
||||
super(inner.start, inner.end, inner.type());
|
||||
this.inner = inner;
|
||||
this.exception = new ParseException(new ParseException.Message(inner.span(), message));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ParseException exception() {
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
25
src/jvmMain/java/mtmc/lang/sea/ast/Statement.java
Normal file
25
src/jvmMain/java/mtmc/lang/sea/ast/Statement.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.ParseException;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public abstract sealed class Statement extends Ast permits StatementBlock, StatementBreak, StatementContinue, StatementDoWhile, StatementExpression, StatementFor, StatementGoto, StatementIf, StatementReturn, StatementSyntaxError, StatementVar, StatementWhile
|
||||
{
|
||||
private Token labelAnchor = null;
|
||||
|
||||
public Statement(Token start, Token end) {
|
||||
super(start, end);
|
||||
}
|
||||
|
||||
public void setLabelAnchor(Token labelAnchor) throws ParseException {
|
||||
if (labelAnchor == null) return;
|
||||
if (this.labelAnchor != null) {
|
||||
throw new ParseException(new ParseException.Message(labelAnchor, "this statement has been labeled twice!!"));
|
||||
}
|
||||
this.labelAnchor = labelAnchor;
|
||||
}
|
||||
|
||||
public Token getLabelAnchor() {
|
||||
return labelAnchor;
|
||||
}
|
||||
}
|
||||
14
src/jvmMain/java/mtmc/lang/sea/ast/StatementBlock.java
Normal file
14
src/jvmMain/java/mtmc/lang/sea/ast/StatementBlock.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class StatementBlock extends Statement {
|
||||
public final List<Statement> statements;
|
||||
|
||||
public StatementBlock(Token start, List<Statement> children, Token end) {
|
||||
super(start, end);
|
||||
this.statements = List.copyOf(children);
|
||||
}
|
||||
}
|
||||
9
src/jvmMain/java/mtmc/lang/sea/ast/StatementBreak.java
Normal file
9
src/jvmMain/java/mtmc/lang/sea/ast/StatementBreak.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class StatementBreak extends Statement {
|
||||
public StatementBreak(Token breakToken) {
|
||||
super(breakToken, breakToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class StatementContinue extends Statement {
|
||||
public StatementContinue(Token continueToken) {
|
||||
super(continueToken, continueToken);
|
||||
}
|
||||
}
|
||||
14
src/jvmMain/java/mtmc/lang/sea/ast/StatementDoWhile.java
Normal file
14
src/jvmMain/java/mtmc/lang/sea/ast/StatementDoWhile.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class StatementDoWhile extends Statement {
|
||||
public final Statement body;
|
||||
public final Expression condition;
|
||||
|
||||
public StatementDoWhile(Token start, Statement body, Expression condition, Token end) {
|
||||
super(start, end);
|
||||
this.body = body;
|
||||
this.condition = condition;
|
||||
}
|
||||
}
|
||||
10
src/jvmMain/java/mtmc/lang/sea/ast/StatementExpression.java
Normal file
10
src/jvmMain/java/mtmc/lang/sea/ast/StatementExpression.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
public final class StatementExpression extends Statement {
|
||||
public final Expression expression;
|
||||
|
||||
public StatementExpression(Expression expression) {
|
||||
super(expression.start, expression.end);
|
||||
this.expression = expression;
|
||||
}
|
||||
}
|
||||
20
src/jvmMain/java/mtmc/lang/sea/ast/StatementFor.java
Normal file
20
src/jvmMain/java/mtmc/lang/sea/ast/StatementFor.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class StatementFor extends Statement {
|
||||
public final Expression initExpression;
|
||||
public final StatementVar initStatement;
|
||||
public final Expression condition;
|
||||
public final Expression inc;
|
||||
public final Statement body;
|
||||
|
||||
public StatementFor(Token start, Expression initExpression, StatementVar initStatement, Expression condition, Expression inc, Statement body) {
|
||||
super(start, body.end);
|
||||
this.initExpression = initExpression;
|
||||
this.initStatement = initStatement;
|
||||
this.condition = condition;
|
||||
this.inc = inc;
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
12
src/jvmMain/java/mtmc/lang/sea/ast/StatementGoto.java
Normal file
12
src/jvmMain/java/mtmc/lang/sea/ast/StatementGoto.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class StatementGoto extends Statement {
|
||||
public final Token label;
|
||||
|
||||
public StatementGoto(Token start, Token label) {
|
||||
super(start, label);
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
16
src/jvmMain/java/mtmc/lang/sea/ast/StatementIf.java
Normal file
16
src/jvmMain/java/mtmc/lang/sea/ast/StatementIf.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class StatementIf extends Statement {
|
||||
public final Expression condition;
|
||||
public final Statement body;
|
||||
public final Statement elseBody;
|
||||
|
||||
public StatementIf(Token start, Expression condition, Statement body, Statement elseBody) {
|
||||
super(start, elseBody == null ? body.end : elseBody.end);
|
||||
this.condition = condition;
|
||||
this.body = body;
|
||||
this.elseBody = elseBody;
|
||||
}
|
||||
}
|
||||
12
src/jvmMain/java/mtmc/lang/sea/ast/StatementReturn.java
Normal file
12
src/jvmMain/java/mtmc/lang/sea/ast/StatementReturn.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class StatementReturn extends Statement {
|
||||
public final Expression value;
|
||||
|
||||
public StatementReturn(Token start, Expression value) {
|
||||
super(start, value == null ? start : value.end);
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
18
src/jvmMain/java/mtmc/lang/sea/ast/StatementSyntaxError.java
Normal file
18
src/jvmMain/java/mtmc/lang/sea/ast/StatementSyntaxError.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.ParseException;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class StatementSyntaxError extends Statement implements SyntaxError {
|
||||
public final ParseException exception;
|
||||
|
||||
public StatementSyntaxError(Token token, ParseException exception) {
|
||||
super(token, token);
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParseException exception() {
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
20
src/jvmMain/java/mtmc/lang/sea/ast/StatementVar.java
Normal file
20
src/jvmMain/java/mtmc/lang/sea/ast/StatementVar.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class StatementVar extends Statement {
|
||||
public final TypeExpr type;
|
||||
public final Token name;
|
||||
public final Expression initValue;
|
||||
|
||||
public StatementVar(TypeExpr type, Token name, Expression initValue) {
|
||||
super(type.start, initValue == null ? name : initValue.end);
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.initValue = initValue;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name.content();
|
||||
}
|
||||
}
|
||||
14
src/jvmMain/java/mtmc/lang/sea/ast/StatementWhile.java
Normal file
14
src/jvmMain/java/mtmc/lang/sea/ast/StatementWhile.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class StatementWhile extends Statement {
|
||||
public final Expression condition;
|
||||
public final Statement body;
|
||||
|
||||
public StatementWhile(Token start, Expression condition, Statement body) {
|
||||
super(start, body.end);
|
||||
this.condition = condition;
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
7
src/jvmMain/java/mtmc/lang/sea/ast/SyntaxError.java
Normal file
7
src/jvmMain/java/mtmc/lang/sea/ast/SyntaxError.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.ParseException;
|
||||
|
||||
public interface SyntaxError extends Error {
|
||||
ParseException exception();
|
||||
}
|
||||
8
src/jvmMain/java/mtmc/lang/sea/ast/TypeDeclaration.java
Normal file
8
src/jvmMain/java/mtmc/lang/sea/ast/TypeDeclaration.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
|
||||
public interface TypeDeclaration {
|
||||
String name();
|
||||
SeaType type();
|
||||
}
|
||||
19
src/jvmMain/java/mtmc/lang/sea/ast/TypeExpr.java
Normal file
19
src/jvmMain/java/mtmc/lang/sea/ast/TypeExpr.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract sealed class TypeExpr extends Ast permits TypeExprArray, TypeExprChar, TypeExprInt, TypeExprRef, TypeExprVoid, TypePointer {
|
||||
private final SeaType type;
|
||||
|
||||
public TypeExpr(Token start, Token end, SeaType type) {
|
||||
super(start, end);
|
||||
this.type = Objects.requireNonNull(type);
|
||||
}
|
||||
|
||||
public SeaType type() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
13
src/jvmMain/java/mtmc/lang/sea/ast/TypeExprArray.java
Normal file
13
src/jvmMain/java/mtmc/lang/sea/ast/TypeExprArray.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class TypeExprArray extends TypeExpr {
|
||||
public final TypeExpr inner;
|
||||
|
||||
public TypeExprArray(TypeExpr inner, Token end) {
|
||||
super(inner.start, end, new SeaType.Pointer(inner.type()));
|
||||
this.inner = inner;
|
||||
}
|
||||
}
|
||||
13
src/jvmMain/java/mtmc/lang/sea/ast/TypeExprChar.java
Normal file
13
src/jvmMain/java/mtmc/lang/sea/ast/TypeExprChar.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class TypeExprChar extends TypeExpr {
|
||||
public final Token token;
|
||||
|
||||
public TypeExprChar(Token token) {
|
||||
super(token, token, SeaType.CHAR);
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
10
src/jvmMain/java/mtmc/lang/sea/ast/TypeExprInt.java
Normal file
10
src/jvmMain/java/mtmc/lang/sea/ast/TypeExprInt.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class TypeExprInt extends TypeExpr {
|
||||
public TypeExprInt(Token token) {
|
||||
super(token, token, SeaType.INT);
|
||||
}
|
||||
}
|
||||
12
src/jvmMain/java/mtmc/lang/sea/ast/TypeExprRef.java
Normal file
12
src/jvmMain/java/mtmc/lang/sea/ast/TypeExprRef.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class TypeExprRef extends TypeExpr {
|
||||
public final TypeDeclaration decl;
|
||||
|
||||
public TypeExprRef(Token name, TypeDeclaration decl) {
|
||||
super(name, name, decl.type());
|
||||
this.decl = decl;
|
||||
}
|
||||
}
|
||||
10
src/jvmMain/java/mtmc/lang/sea/ast/TypeExprVoid.java
Normal file
10
src/jvmMain/java/mtmc/lang/sea/ast/TypeExprVoid.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class TypeExprVoid extends TypeExpr {
|
||||
public TypeExprVoid(Token token) {
|
||||
super(token, token, SeaType.VOID);
|
||||
}
|
||||
}
|
||||
13
src/jvmMain/java/mtmc/lang/sea/ast/TypePointer.java
Normal file
13
src/jvmMain/java/mtmc/lang/sea/ast/TypePointer.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.SeaType;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
public final class TypePointer extends TypeExpr {
|
||||
public final TypeExpr component;
|
||||
|
||||
public TypePointer(TypeExpr component, Token star) {
|
||||
super(component.start, star, new SeaType.Pointer(component.type()));
|
||||
this.component = component;
|
||||
}
|
||||
}
|
||||
22
src/jvmMain/java/mtmc/lang/sea/ast/Unit.java
Normal file
22
src/jvmMain/java/mtmc/lang/sea/ast/Unit.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package mtmc.lang.sea.ast;
|
||||
|
||||
import mtmc.lang.sea.Symbol;
|
||||
import mtmc.lang.sea.Token;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
public final class Unit extends Ast {
|
||||
public final String source;
|
||||
public final String filename;
|
||||
public final List<Declaration> declarations;
|
||||
public final LinkedHashMap<String, Symbol> symbols;
|
||||
|
||||
public Unit(String filename, String source, List<Declaration> declarations, LinkedHashMap<String, Symbol> globals) {
|
||||
super(Token.SOF, Token.EOF);
|
||||
this.source = source;
|
||||
this.filename = filename;
|
||||
this.declarations = declarations;
|
||||
this.symbols = globals;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user