diff --git a/README.md b/README.md index 6d5451d..5064098 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ -# CobaltScript -A small programming language designed for general purpose scripting and for learning interpreter design +# Cobalt +Cobalt is a small programming language designed for general purpose and systems level scripting. This project follows very closely to the curriculum from [Crafting Interpreters](http://craftinginterpreters.com/) by Robert Nystrom, and is intended to be a pet project for myself to learn programming language design and interpreter design concepts. + +Currently, Cobalt follows the same grammer and design structure as [Lox](https://github.com/munificent/craftinginterpreters), the language featured in Nystrom's book. However, I eventually plan to mutate Cobalt from these design patterns and create a unique syntax and structure once I have reached a high enough proficiency. + +This project is a **work in progress**, so some things might be a bit broken. YMMV :) diff --git a/cobalt/Cobalt.java b/cobalt/Cobalt.java new file mode 100644 index 0000000..dc164e9 --- /dev/null +++ b/cobalt/Cobalt.java @@ -0,0 +1,68 @@ +package cobalt; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +public class Cobalt { + + static boolean hadError = false; + + public static void main(String[] args) throws IOException { + if (args.length > 1) { + System.out.println("Usage: cobalt [script]"); + System.exit(64); + } else if (args.length == 1) { + //runFile(args[0]); + } else { + //runPrompt() + } + } + + private static void runFile(String path) throws IOException { + byte[] bytes = Files.readAllBytes(Paths.get(path)); + run(new String(bytes, Charset.defaultCharset())); + if (hadError) System.exit(65); + } + + private static void runPrompt() throws IOException { + InputStreamReader input = new InputStreamReader(System.in); + BufferedReader reader = new BufferedReader(input); + + for (;;) { + System.out.print("> "); + String line = reader.readLine(); + if (line == null) break; + run(line); + hadError = false; + } + } + + private static void run(String source) { + // Wont compile since we don't use the standard Java Scanner, + // gets implemented further in the textbook + Scanner scanner = new Scanner(source); + // Same situation for Token type + List tokens = scanner.scanTokens(); + + for (Token token : tokens) { + System.out.println(token); + } + } + + static void error(int line, String message) { + report(line, "", message); + } + + private static void report(int line, String where, String message) { + System.err.println( + "[line " + line + "] Error" + where + ": " + message + ); + hadError = true; + + } +} \ No newline at end of file diff --git a/cobalt/Scanner.java b/cobalt/Scanner.java new file mode 100644 index 0000000..1dfe59b --- /dev/null +++ b/cobalt/Scanner.java @@ -0,0 +1,34 @@ +package cobalt; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static cobalt.TokenType.*; + +class Scanner { + private final String source; + private final List tokens = new ArrayList<>(); + private int start = 0; + private int current = 0; + private int line = 0; + + Scanner(String source) { + this.source = source; + } + + List scanTokens() { + while (!isAtEnd()) { + start = current; + scanTokens(); + } + + tokens.add(new Token(EOF, "", null, line)); + return tokens; + } + + private boolean isAtEnd() { + return current >= source.length(); + } +} \ No newline at end of file diff --git a/cobalt/Token.java b/cobalt/Token.java new file mode 100644 index 0000000..f5afaac --- /dev/null +++ b/cobalt/Token.java @@ -0,0 +1,19 @@ +package cobalt; + +class Token { + final TokenType type; + final String lexeme; + final Object literal; + final int line; + + Token(TokenType type, String lexeme, Object literal, int line) { + this.type = type; + this.lexeme = lexeme; + this.literal = literal; + this.line = line; + } + + public String toString() { + return type + " " + lexeme + " " + literal; + } +} \ No newline at end of file diff --git a/cobalt/TokenType.java b/cobalt/TokenType.java new file mode 100644 index 0000000..c73c928 --- /dev/null +++ b/cobalt/TokenType.java @@ -0,0 +1,20 @@ +package cobalt; + +enum TokenType { + // Single character tokens. + LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE, + COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR, + + // One or two character tokens. + BANG, BANG_EQUAL, EQUAL, EQUAL_EQUAL, + GREATER, GREATER_EQUAL, LESS, LESS_EQUAL, + + // Literals + IDENTIFIER, STRING, NUMBER, + + // Keywords + AND, CLASS, ELSE, FALSE, FUN, FOR, IF, NIL, OR, + PRINT, RETURN, SUPER, THIS, TRUE, VAR, WHILE, + + EOF +} \ No newline at end of file diff --git a/include/lexer.h b/include/lexer.h deleted file mode 100644 index 1109ab2..0000000 --- a/include/lexer.h +++ /dev/null @@ -1,14 +0,0 @@ -#include - -#ifndef LEXER_H -#define LEXER_H - -class Lexer -{ - private: - std::string extension = ".prog"; - public: - Lexer(std::string &file_name); -}; - -#endif \ No newline at end of file diff --git a/include/parser.h b/include/parser.h deleted file mode 100644 index 3ed0240..0000000 --- a/include/parser.h +++ /dev/null @@ -1,14 +0,0 @@ -#include - -#ifndef PARSER_H -#define PARSER_H - -class Parser -{ - private: - - public: - Parser(std::string input_file); -}; - -#endif \ No newline at end of file diff --git a/include/token.h b/include/token.h deleted file mode 100644 index e69de29..0000000 diff --git a/makefile b/makefile deleted file mode 100644 index 48073c5..0000000 --- a/makefile +++ /dev/null @@ -1,20 +0,0 @@ - -#OBJS specifies which files to compile as part of the project -OBJS = $(wildcard src/*.cpp) - -#CC specifies which compiler we're using -CC = g++ - -#COMPILER_FLAGS specifies the additional compilation options we're using -# -w suppresses all warnings -COMPILER_FLAGS = -w - -#LINKER_FLAGS specifies the libraries we're linking against -LINKER_FLAGS = - -#OBJ_NAME specifies the name of our exectuable -OBJ_NAME = cobalt - -#This is the target that compiles our executable -all : $(OBJS) - $(CC) $(OBJS) $(COMPILER_FLAGS) $(LINKER_FLAGS) -o $(OBJ_NAME) diff --git a/script.prog b/script.prog deleted file mode 100644 index dd449f8..0000000 --- a/script.prog +++ /dev/null @@ -1,3 +0,0 @@ -hello world, this is a lexer test -hello world -Kanye's new name is Ye \ No newline at end of file diff --git a/src/lexer.cpp b/src/lexer.cpp deleted file mode 100644 index e2718ef..0000000 --- a/src/lexer.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include -#include "../include/lexer.h" - -char c; -FILE* input_file; - -Lexer::Lexer(std::string &file_name) { - input_file = fopen(file_name.c_str(),"r"); - if(input_file == nullptr) { - std::cout << "[Error] Script " << input_file << " could not be read\n"; - exit(1); - } - - c = getc(input_file); - if (c == EOF) { - //do something related to eof here? - fclose(input_file); - } -} - -char nextChar() { - if (c != EOF) { - c = getc(input_file); - } else { - c = EOF; - } - return c; -} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 5a59783..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#include - -#include "../include/lexer.h" - -int main(int argc, char *argv[]) { - if (argc > 1) { - std::string file_name(argv[1]); - Lexer lex(file_name); - } else { - std::cout << "[Error] No input file provided\n"; - } - return 0; -} \ No newline at end of file diff --git a/src/parser.cpp b/src/parser.cpp deleted file mode 100644 index f60a633..0000000 --- a/src/parser.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -#include "../include/parser.h" - -Parser::Parser(std::string input_file) { - -} \ No newline at end of file diff --git a/src/token.cpp b/src/token.cpp deleted file mode 100644 index e69de29..0000000