summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorElias Haugsbakk <[email protected]>2026-09-19 19:38:04 +0200
committerElias Haugsbakk <[email protected]>2026-09-19 19:53:49 +0200
commit6b139769f5ac88221991689ba1917d3e307dc2ef (patch)
treea61b18a8527ed425699708a00617be11f3b3d270 /src/main
parent52a63a487f9d0102db339419aa392f9cd425c0c4 (diff)
add variable declaration to parser
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/IRGeneration/IRGenerator.java2
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/Parser.java248
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/Type.java12
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Expression.java2
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Identifier.java12
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/literal/StringLiteral.java (renamed from src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/StringLiteral.java)4
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Assignment.java13
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/ExpressionStatement.java5
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/IdentifierDeclaration.java22
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Statement.java2
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/semanticAnalysis/Analyzer.java2
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/tokenization/Lexer.java29
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/tokenization/Token.java2
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/tokenization/TokenType.java8
14 files changed, 306 insertions, 57 deletions
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/IRGeneration/IRGenerator.java b/src/main/java/no/eliashaugsbakk/kompilator/IRGeneration/IRGenerator.java
index 55b349e..ffbccb6 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/IRGeneration/IRGenerator.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/IRGeneration/IRGenerator.java
@@ -6,7 +6,7 @@ import no.eliashaugsbakk.kompilator.parsing.AST;
import no.eliashaugsbakk.kompilator.parsing.node.Program;
import no.eliashaugsbakk.kompilator.parsing.node.expression.Expression;
import no.eliashaugsbakk.kompilator.parsing.node.expression.FunctionCall;
-import no.eliashaugsbakk.kompilator.parsing.node.expression.StringLiteral;
+import no.eliashaugsbakk.kompilator.parsing.node.expression.literal.StringLiteral;
import no.eliashaugsbakk.kompilator.parsing.node.statement.ExpressionStatement;
import no.eliashaugsbakk.kompilator.parsing.node.statement.Statement;
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/Parser.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/Parser.java
index 712df22..7f9b6c9 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/parsing/Parser.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/Parser.java
@@ -1,83 +1,255 @@
package no.eliashaugsbakk.kompilator.parsing;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.ASSIGN;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.COLON;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.COMMA;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.EOF;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.IDENTIFIER;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.KEYWORD;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.LPAREN;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.NULLABLE;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.RPAREN;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.SEMICOLON;
-import static no.eliashaugsbakk.kompilator.tokenization.TokenType.STRING;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.STRING_LITERAL;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.TYPE;
import java.util.ArrayList;
import java.util.List;
import no.eliashaugsbakk.kompilator.parsing.node.Program;
import no.eliashaugsbakk.kompilator.parsing.node.expression.Expression;
import no.eliashaugsbakk.kompilator.parsing.node.expression.FunctionCall;
-import no.eliashaugsbakk.kompilator.parsing.node.expression.StringLiteral;
+import no.eliashaugsbakk.kompilator.parsing.node.expression.Identifier;
+import no.eliashaugsbakk.kompilator.parsing.node.expression.literal.StringLiteral;
+import no.eliashaugsbakk.kompilator.parsing.node.statement.Assignment;
import no.eliashaugsbakk.kompilator.parsing.node.statement.ExpressionStatement;
+import no.eliashaugsbakk.kompilator.parsing.node.statement.IdentifierDeclaration;
+import no.eliashaugsbakk.kompilator.parsing.node.statement.Statement;
import no.eliashaugsbakk.kompilator.tokenization.Token;
+/*
+ The goal of parsing is to create the AST.
+ The root node is the program itself, which can only hold statements.
+
+ Statements:
+ - Is an action which executes something
+ - Has no return or implicit value
+ - Must end with a semicolon
+ - A statement may contain expressions
+ - An expression cannot contain a statement
+
+ Expressions:
+ - Returns or produces a value
+ - Does not end with a semicolon
+ - Can be nested instide other expressions or a statement
+ - Examples:
+ - Literals
+ - Identifiers
+ - Binary Operations
+ - Function calls
+ */
+
+
public class Parser {
private final List<Token> tokens;
- private int position = 0;
+ private final Program rootNode;
+ private int current = 0;
public Parser(List<Token> tokens) {
this.tokens = tokens;
+ this.rootNode = new Program();
}
public AST parse() throws ParserException {
- Program rootNode = new Program();
+ while (current < tokens.size()) {
+ Token token = tokens.get(current);
+
+ // End of File
+ if (token.type() == EOF) {
+ break;
+ }
+
+ // root node must contain only statements
+ Statement stmt = parseStatement();
+ rootNode.addStatement(stmt);
+ }
+ return new AST(rootNode);
+ }
- while (position < tokens.size()) {
- Token token = tokens.get(position);
+ private Statement parseStatement() throws ParserException {
+ // multiple statements are supported for v0.0.2;
+ // identifier declaration: x: string = "hello"; (with expression)
+ // identifier declaration: x: string; (without expression)
+ // assignment: x = "hello"; (identifier gets assigned an expression)
+ // expression statements: print(x); (function without a return value)
- if (token.type() == KEYWORD) {
- String functionName = token.value();
- position++;
- List<Expression> arguments = parseArguments();
+ // each statement must either start with a keyword or an identifier
+ Token token = tokens.get(current);
- FunctionCall functionCall = new FunctionCall(functionName, arguments);
- rootNode.addStatement(new ExpressionStatement(functionCall));
- } else if (token.type() == EOF) {
- break;
- } else {
- throw new ParserException(token.line(), token.colum(),
- "Unexpected token: " + token.value());
- }
+ // only keyword implemented is "skriv", so calling parseExpression right away
+ if (token.type() == KEYWORD) {
+ return parseExpressionStatement();
}
- return new AST(rootNode);
+ // must be identifier declaration or an assignment
+ else if (token.type() == IDENTIFIER) {
+ return parseIdentifierStatement();
+ }
+
+ // must be some other token which is not a statement
+ else {
+ throw new ParserException(token.line(), token.column(), "Unexpected token: " + token.value());
+ }
}
- List<Expression> parseArguments() throws ParserException {
- List<Expression> arguments = new ArrayList<>();
+ private ExpressionStatement parseExpressionStatement() throws ParserException {
+ // this can be any expression used as a statement
+ // print(x);
+ // 5 + 6;
+ // "hello";
+
+ Expression expression = parseExpression();
+ expectSemicolon();
+ return new ExpressionStatement(expression);
+ }
+
+
+
+ private Statement parseIdentifierStatement() throws ParserException {
+ // this is either:
+ // - declaration of a new variable with an associated value
+ // - declaration of a new variable without an associated value
+ // - reassigning an existing variable
+
+ /*
+ x: string?; IDENTIFIER, COLON, TYPE, SEMICOLON
+ x: string = "string"; IDENTIFIER, COLON, TYPE, ASSIGN, STRING, SEMICOLON
+ x = "string"; IDENTIFIER, ASSIGN, STRING, SEMICOLON
+ */
+
+ String identifier = tokens.get(current).value();
+ current++;
+
+ Token next = tokens.get(current);
+
+ if (next.type() == COLON) {
+ // x: string = "hello";
+ return parseDeclaration(identifier);
+ } else if (next.type() == ASSIGN) {
+ // x = "hello";
+ return parseAssignment(identifier);
+ } else {
+ throw new ParserException(next.line(), next.column(), "Expected : or = after identifier");
+ }
+ }
- if (position >= tokens.size() || tokens.get(position).type() != LPAREN) {
- throw new ParserException(tokens.get(position).line(), tokens.get(position).colum(),
- "Unexpected token:" + tokens.get(position).value() + "\n Expected: (");
+ private Statement parseDeclaration(String identifier) throws ParserException {
+ // x: type;
+ current++; // skip colon
+
+ Type type = parseType();
+ Expression initializer = null;
+
+ // x: type = "hello";
+ if (tokens.get(current).type() == ASSIGN) {
+ current++; // skip =
+ initializer = parseExpression();
+ }
+
+ expectSemicolon();
+ return new IdentifierDeclaration(identifier, type, initializer);
+ }
+
+ private Statement parseAssignment(String identifier) throws ParserException {
+ // x = value;
+ current++; // skip =
+
+ Expression value = parseExpression();
+ expectSemicolon();
+
+ return new Assignment(identifier, value);
+ }
+
+ private Type parseType() throws ParserException {
+ Token token = tokens.get(current);
+ if (token.type() != TYPE) {
+ throw new ParserException(token.line(), token.column(),
+ "Expected type, got: " + token.value());
}
- position++;
+ current++;
+
+ String typeName = token.value();
+ boolean nullable = false;
- while (position < tokens.size() && tokens.get(position).type() != RPAREN) {
- if (tokens.get(position).type() == STRING) {
- arguments.add(new StringLiteral(tokens.get(position).value()));
+ if (current < tokens.size() && tokens.get(current).type() == NULLABLE) {
+ nullable = true;
+ current++;
+ }
+
+ return new Type(typeName, nullable);
+ }
+
+ private Expression parseExpression() throws ParserException {
+ // an expression produces a value and may contain other expressions
+ // implemented for v0.0.2 are:
+ // "string" - STRING_LITERAL
+ // my_var - IDENTIFIER
+
+ Token token = tokens.get(current);
+ current++;
+
+ if (token.type() == STRING_LITERAL) {
+ return new StringLiteral(token.value());
+ } else if (token.type() == IDENTIFIER || token.type() == KEYWORD) {
+ // could be function call or just identifier reference
+ if (current < tokens.size() && tokens.get(current).type() == LPAREN) {
+ current--;
+ return parseFunctionCall();
}
- position++;
+ return new Identifier(token.value());
+ } else {
+ throw new ParserException(token.line(), token.column(),
+ "Unexpected token: " + token.value() + ". Expected an expression");
}
+ }
+
+ private FunctionCall parseFunctionCall() throws ParserException {
+ String name = tokens.get(current).value();
+ current++;
+ List<Expression> arguments = parseFunctionArguments();
+ return new FunctionCall(name, arguments);
+ }
- if (position >= tokens.size()) {
- throw new ParserException(-1, -1, "Unexpected end of file, expected )");
+ private List<Expression> parseFunctionArguments() throws ParserException {
+ List<Expression> arguments = new ArrayList<>();
+
+ if (tokens.get(current).type() != LPAREN) {
+ throw new ParserException(tokens.get(current).line(), tokens.get(current).column(),
+ "Expected (");
}
- position++;
+ current++; // skip (
+
+ while (current < tokens.size() && tokens.get(current).type() != RPAREN) {
+ arguments.add(parseExpression()); // parseExpression() increments current
- if (position >= tokens.size() || tokens.get(position).type() != SEMICOLON) {
- throw new ParserException(position < tokens.size() ? tokens.get(position).line() : -1,
- position < tokens.size() ? tokens.get(position).colum() : -1,
- "Unexpected token: " + (position < tokens.size() ? tokens.get(position).value() : "EOF") +
- "\n" + "Expected: ;");
+ if (tokens.get(current).type() == COMMA) {
+ current++; // skip comma
+ }
+ }
+
+ if (current >= tokens.size() || tokens.get(current).type() != RPAREN) {
+ throw new ParserException(tokens.get(current).line(), tokens.get(current).column(),
+ "Expected )");
}
- position++;
+ current++; // skip )
return arguments;
}
+
+ private void expectSemicolon() throws ParserException {
+ if (current >= tokens.size() || tokens.get(current).type() != SEMICOLON) {
+ throw new ParserException(-1, -1, "Expected ;");
+ }
+ current++;
+ }
}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/Type.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/Type.java
new file mode 100644
index 0000000..64305da
--- /dev/null
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/Type.java
@@ -0,0 +1,12 @@
+package no.eliashaugsbakk.kompilator.parsing;
+
+public class Type {
+ final String type;
+ final boolean nullable;
+
+ public Type(String type, boolean nullable) {
+ this.type = type;
+ this.nullable = nullable;
+ }
+}
+
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Expression.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Expression.java
index 6ca58b2..18fc585 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Expression.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Expression.java
@@ -4,7 +4,7 @@ import no.eliashaugsbakk.kompilator.parsing.node.ASTNode;
/**
* Base class for all expression nodes.
- * An expression is a piece of code that evaluates to a value.
+ * An expression is a piece of code that evaluates to a value. (i.e., returns a value)
* Expressions cannot stand alone as statements; they must be used within statements.
* <p>
* Examples:
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Identifier.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Identifier.java
new file mode 100644
index 0000000..c1f475f
--- /dev/null
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Identifier.java
@@ -0,0 +1,12 @@
+package no.eliashaugsbakk.kompilator.parsing.node.expression;
+
+/**
+ * Resolves to a variable's value
+ */
+public class Identifier extends Expression {
+ final String name;
+
+ public Identifier(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/StringLiteral.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/literal/StringLiteral.java
index 67ce405..82402ed 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/StringLiteral.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/literal/StringLiteral.java
@@ -1,4 +1,6 @@
-package no.eliashaugsbakk.kompilator.parsing.node.expression;
+package no.eliashaugsbakk.kompilator.parsing.node.expression.literal;
+
+import no.eliashaugsbakk.kompilator.parsing.node.expression.Expression;
/**
* Represents a string literal expression (e.g., "Hello, World").
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Assignment.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Assignment.java
new file mode 100644
index 0000000..a54a891
--- /dev/null
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Assignment.java
@@ -0,0 +1,13 @@
+package no.eliashaugsbakk.kompilator.parsing.node.statement;
+
+import no.eliashaugsbakk.kompilator.parsing.node.expression.Expression;
+
+public class Assignment extends Statement {
+ final String identifier;
+ final Expression expression;
+
+ public Assignment(String identifier, Expression expression) {
+ this.identifier = identifier;
+ this.expression = expression;
+ }
+}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/ExpressionStatement.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/ExpressionStatement.java
index 64bc0a8..b810a04 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/ExpressionStatement.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/ExpressionStatement.java
@@ -2,6 +2,11 @@ package no.eliashaugsbakk.kompilator.parsing.node.statement;
import no.eliashaugsbakk.kompilator.parsing.node.expression.Expression;
+/**
+ * A statement which holds an expression.
+ * print("hello"); does not have a return value; it is a statement, but it is also
+ * function call.
+ */
public class ExpressionStatement extends Statement {
public Expression expression;
public ExpressionStatement(Expression expression) {
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/IdentifierDeclaration.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/IdentifierDeclaration.java
new file mode 100644
index 0000000..e7db477
--- /dev/null
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/IdentifierDeclaration.java
@@ -0,0 +1,22 @@
+package no.eliashaugsbakk.kompilator.parsing.node.statement;
+
+import no.eliashaugsbakk.kompilator.parsing.Type;
+import no.eliashaugsbakk.kompilator.parsing.node.expression.Expression;
+
+public class IdentifierDeclaration extends Statement {
+ // identifier name: [my_var]: type = 4;
+ final String identifier;
+
+ // identifier type: my_var: [type] = 4;
+ final Type type;
+
+ // identifier initialization: my_var: type [4];
+ // may be null: my_var: type?;
+ final Expression expression; // may be null: x: int?;
+
+ public IdentifierDeclaration(String identifier, Type type, Expression expression) {
+ this.identifier = identifier;
+ this.type = type;
+ this.expression = expression;
+ }
+}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Statement.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Statement.java
index fc52f9a..aed21ad 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Statement.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Statement.java
@@ -5,9 +5,11 @@ import no.eliashaugsbakk.kompilator.parsing.node.ASTNode;
/**
* Base class for all statement nodes.
* A statement is a top-level line of code that performs an action.
+ * No return value.
* <p>
* Examples:
* - print("Hello"); (function call statement)
+ * x my_value = my_func("Hello"); (not a statement - it has a return value)
* - var x: int = 5; (variable declaration statement)
* - if (x > 0) { } (conditional statement)
*/
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/semanticAnalysis/Analyzer.java b/src/main/java/no/eliashaugsbakk/kompilator/semanticAnalysis/Analyzer.java
index 9452fc1..b7cc7af 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/semanticAnalysis/Analyzer.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/semanticAnalysis/Analyzer.java
@@ -6,7 +6,7 @@ import no.eliashaugsbakk.kompilator.parsing.AST;
import no.eliashaugsbakk.kompilator.parsing.node.Program;
import no.eliashaugsbakk.kompilator.parsing.node.expression.Expression;
import no.eliashaugsbakk.kompilator.parsing.node.expression.FunctionCall;
-import no.eliashaugsbakk.kompilator.parsing.node.expression.StringLiteral;
+import no.eliashaugsbakk.kompilator.parsing.node.expression.literal.StringLiteral;
import no.eliashaugsbakk.kompilator.parsing.node.statement.ExpressionStatement;
import no.eliashaugsbakk.kompilator.parsing.node.statement.Statement;
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Lexer.java b/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Lexer.java
index c185650..53c7b53 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Lexer.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Lexer.java
@@ -6,15 +6,17 @@ import static no.eliashaugsbakk.kompilator.tokenization.LexerState.IN_TYPE;
import static no.eliashaugsbakk.kompilator.tokenization.LexerState.IN_WORD;
import static no.eliashaugsbakk.kompilator.tokenization.LexerState.NORMAL;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.ASSIGN;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.COMMA;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.EOF;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.IDENTIFIER;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.KEYWORD;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.LPAREN;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.NULLABLE;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.RPAREN;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.SEMICOLON;
-import static no.eliashaugsbakk.kompilator.tokenization.TokenType.STRING;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.STRING_LITERAL;
import static no.eliashaugsbakk.kompilator.tokenization.TokenType.TYPE;
-import static no.eliashaugsbakk.kompilator.tokenization.TokenType.TYPE_DECLARATION;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.COLON;
import java.util.ArrayList;
import java.util.List;
@@ -47,12 +49,11 @@ public class Lexer {
}
current = input.charAt(position);
- if (!Character.isWhitespace(current)) {
-
+ if (state == IN_STRING) {
+ inString();
+ } else if (!Character.isWhitespace(current)) {
if (state == IN_WORD) {
inWord();
- } else if (state == IN_STRING) {
- inString();
} else if (state == IN_TYPE) {
inType();
}
@@ -76,7 +77,7 @@ public class Lexer {
wordBuffer.append(current);
} else if (current == ':') {
- tokens.add(new Token(TYPE_DECLARATION, ":", line, column));
+ tokens.add(new Token(COLON, ":", line, column));
state = IN_TYPE;
} else if (current == '=') {
@@ -87,11 +88,18 @@ public class Lexer {
tokens.add(new Token(RPAREN, Character.toString(current), line, column));
} else if (current == ';') {
tokens.add(new Token(SEMICOLON, Character.toString(current), line, column));
+ } else if (current == ',') {
+ tokens.add(new Token(COMMA, Character.toString(current), line, column));
}
}
private void inType() {
- if (current == '=' || current == ';') {
+ if (current == '?') {
+ state = NORMAL;
+ tokens.add(new Token(TYPE, wordBuffer.toString(), line, column - wordBuffer.length()));
+ tokens.add(new Token(NULLABLE, "?", line, column));
+ clearWordBuffer();
+ } else if (current == '=' || current == ';') {
state = NORMAL;
tokens.add(new Token(TYPE, wordBuffer.toString(), line, column - wordBuffer.length()));
clearWordBuffer();
@@ -101,11 +109,10 @@ public class Lexer {
}
private void inString() {
- if (current == '"') {
- position++; // skip closing "
+ if (current == '"') { // closing " gets skipped implicitly
current = input.charAt(position);
state = NORMAL;
- tokens.add(new Token(STRING, wordBuffer.toString(), line, column));
+ tokens.add(new Token(STRING_LITERAL, wordBuffer.toString(), line, column));
wordBuffer.delete(0, wordBuffer.length());
} else {
wordBuffer.append(current);
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Token.java b/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Token.java
index 09c5d83..1cab703 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Token.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Token.java
@@ -1,4 +1,4 @@
package no.eliashaugsbakk.kompilator.tokenization;
-public record Token(TokenType type, String value, int line, int colum) {
+public record Token(TokenType type, String value, int line, int column) {
}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/tokenization/TokenType.java b/src/main/java/no/eliashaugsbakk/kompilator/tokenization/TokenType.java
index 1d6382e..3a1d4ba 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/tokenization/TokenType.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/tokenization/TokenType.java
@@ -3,12 +3,14 @@ package no.eliashaugsbakk.kompilator.tokenization;
public enum TokenType {
KEYWORD, // print, var, if, while, function, etc.
IDENTIFIER, // variable_1
- STRING, // "Hello, World!"
- TYPE_DECLARATION, // : (x[:] int = ...)
- TYPE, // String, i32, i16?, my_type, ... (? makes nullable)
+ STRING_LITERAL, // "Hello, World!"
+ COLON, // : (x[:] int = ...)
+ TYPE, // string, i32, i16?, my_type, ... (? makes nullable)
ASSIGN, // =
+ NULLABLE, // ? (x = string?;)
LPAREN, // (
RPAREN, // )
SEMICOLON, // ;
+ COMMA, // ,
EOF // End of File
}