├── tests ├── include.ter.result ├── hello.ter.result ├── library.ter ├── errorString.ter ├── args.ter.args ├── hello.ter ├── functions.ter.result ├── errorString.ter.error ├── args.ter.result ├── include.ter ├── loops.ter.result ├── classes.ter.result ├── args.ter ├── incdec.ter.result ├── operators.ter.result ├── bitwiseShift.ter.result ├── limits.ter.result ├── bitwiseOperators.ter.result ├── operators.modulo.ter.result ├── limits.ter ├── incdec.ter ├── operators.ter ├── loops.ter ├── bitwiseShift.ter ├── functions.ter ├── classes.ter ├── bitwiseOperators.ter ├── operators.modulo.ter ├── run.sh └── run.bat ├── logo-ter-terlang.png ├── src ├── utils │ ├── RuntimeError.cpp │ ├── RuntimeError.hpp │ ├── Debug.hpp │ ├── Helpers.hpp │ └── Debug.cpp ├── Ter.hpp ├── parser │ ├── IncludeRun.hpp │ ├── IncludeRun.cpp │ ├── Visitor.hpp │ ├── Parser.hpp │ ├── Stmt.cpp │ ├── Expr.cpp │ ├── Stmt.hpp │ ├── Expr.hpp │ └── Parser.cpp ├── interpreter │ ├── BuiltinFactory.hpp │ ├── ArrayType.hpp │ ├── Callable.hpp │ ├── Function.hpp │ ├── ArrayType.cpp │ ├── Instance.hpp │ ├── Class.hpp │ ├── Environment.hpp │ ├── Class.cpp │ ├── Function.cpp │ ├── Instance.cpp │ ├── BuiltinFactory.cpp │ ├── Builtin.hpp │ ├── Environment.cpp │ ├── Resolver.hpp │ ├── Interpreter.hpp │ ├── Builtin.cpp │ ├── Resolver.cpp │ └── Interpreter.cpp ├── tokenizer │ ├── Token.hpp │ ├── TokenType.hpp │ ├── Token.cpp │ ├── Scanner.hpp │ └── Scanner.cpp ├── main.cpp └── Ter.cpp ├── .gitignore ├── debug.ter ├── CMakeLists.txt ├── README.md └── LICENSE /tests/include.ter.result: -------------------------------------------------------------------------------- 1 | 18 2 | -------------------------------------------------------------------------------- /tests/hello.ter.result: -------------------------------------------------------------------------------- 1 | Hello Ter! 2 | -------------------------------------------------------------------------------- /tests/library.ter: -------------------------------------------------------------------------------- 1 | auto value=18 2 | -------------------------------------------------------------------------------- /tests/errorString.ter: -------------------------------------------------------------------------------- 1 | auto a="this is a text 2 | -------------------------------------------------------------------------------- /tests/args.ter.args: -------------------------------------------------------------------------------- 1 | first second --third "My Four" -------------------------------------------------------------------------------- /tests/hello.ter: -------------------------------------------------------------------------------- 1 | auto a="Hello Ter!" 2 | output(a) 3 | -------------------------------------------------------------------------------- /tests/functions.ter.result: -------------------------------------------------------------------------------- 1 | My content 2 | 12 3 | 7 4 | 13 -------------------------------------------------------------------------------- /tests/errorString.ter.error: -------------------------------------------------------------------------------- 1 | error: line: 2: Unterminated string. 2 | -------------------------------------------------------------------------------- /tests/args.ter.result: -------------------------------------------------------------------------------- 1 | [first, second, --third, "My, Four"] 2 | second 3 | -------------------------------------------------------------------------------- /tests/include.ter: -------------------------------------------------------------------------------- 1 | include("./library.ter") 2 | output(value); // 18 3 | -------------------------------------------------------------------------------- /tests/loops.ter.result: -------------------------------------------------------------------------------- 1 | 0 | 1 | 2 | 3 | 4 | 2 | 0 | 1 | 2 | 3 | 4 | 3 | -------------------------------------------------------------------------------- /tests/classes.ter.result: -------------------------------------------------------------------------------- 1 | Cat name is: Bob 2 | I am dog! 3 | Human: Peter 4 | -------------------------------------------------------------------------------- /tests/args.ter: -------------------------------------------------------------------------------- 1 | auto params = args() 2 | output(params) 3 | output(params[1]) 4 | -------------------------------------------------------------------------------- /tests/incdec.ter.result: -------------------------------------------------------------------------------- 1 | Increment 2 | 1|2|3 3 | Decrement 4 | 3|2|1 5 | -------------------------------------------------------------------------------- /tests/operators.ter.result: -------------------------------------------------------------------------------- 1 | 5 2 | -1 3 | 6 4 | 0.666667 5 | 2 6 | 2 7 | 3 8 | 1 9 | -------------------------------------------------------------------------------- /logo-ter-terlang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terroo/terlang/HEAD/logo-ter-terlang.png -------------------------------------------------------------------------------- /tests/bitwiseShift.ter.result: -------------------------------------------------------------------------------- 1 | Shift left 2 | 4503599627370496|36028797018963968|4|65500 3 | Shift right 4 | 1|8|0|65500 5 | -------------------------------------------------------------------------------- /tests/limits.ter.result: -------------------------------------------------------------------------------- 1 | 9007199254740991 2 | 9007199254740992 3 | 9007199254740992 4 | -9007199254740991 5 | -9007199254740992 6 | -9007199254740992 7 | -------------------------------------------------------------------------------- /tests/bitwiseOperators.ter.result: -------------------------------------------------------------------------------- 1 | 0|0|0|-1 2 | 0|-1|-1|0 3 | 1|-1|-2|-9007199254740992 4 | 6004799503160660|-3002399751580329|-9007199254740989|-6004799503160662 5 | -------------------------------------------------------------------------------- /src/utils/RuntimeError.cpp: -------------------------------------------------------------------------------- 1 | #include "RuntimeError.hpp" 2 | 3 | RuntimeError::RuntimeError(const Token& token, const std::string& message) : 4 | std::runtime_error{message}, token{token} {} 5 | -------------------------------------------------------------------------------- /tests/operators.modulo.ter.result: -------------------------------------------------------------------------------- 1 | Regular 2 | 1|1|-1|-1|0 3 | Limit 53 bits 4 | 1|-0|9007199254740990|1 5 | Floating point 6 | 1.500000|-1.200000|0.100000 7 | Zero 8 | -nan|-nan|-nan 9 | -------------------------------------------------------------------------------- /tests/limits.ter: -------------------------------------------------------------------------------- 1 | auto a=9007199254740990 2 | for(auto i = 0; i < 3; ++i){ 3 | a=a+1 4 | output(a) 5 | } 6 | a=-9007199254740990 7 | for(auto i = 0; i < 3; ++i){ 8 | a=a-1 9 | output(a) 10 | } 11 | -------------------------------------------------------------------------------- /tests/incdec.ter: -------------------------------------------------------------------------------- 1 | auto a=1 2 | output(" Increment") 3 | out(a++) out("|") 4 | out(a) out("|") 5 | output(++a) 6 | output(" Decrement") 7 | out(a--) out("|") 8 | out(a) out("|") 9 | output(--a) 10 | -------------------------------------------------------------------------------- /tests/operators.ter: -------------------------------------------------------------------------------- 1 | auto a=2; 2 | auto b=3; 3 | 4 | output(a+b); 5 | output(a-b); 6 | output(a*b); 7 | output(a/b); 8 | output(a%b); 9 | output(a&b); 10 | output(a|b); 11 | output(a^b); 12 | /* TODO 13 | output(a<>b); 15 | */ -------------------------------------------------------------------------------- /tests/loops.ter: -------------------------------------------------------------------------------- 1 | for(auto i = 0; i < 5; ++i){ // Or i++ 2 | out(to_string(i) + " | ") 3 | } 4 | out("\n") // 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | auto i = 0; 8 | while(i < 5){ 9 | out(to_string(i) + " | ") 10 | ++i; 11 | } 12 | out("\n") // 0 | 1 | 2 | 3 | 4 | 13 | -------------------------------------------------------------------------------- /src/utils/RuntimeError.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../tokenizer/Token.hpp" 5 | 6 | class RuntimeError : public std::runtime_error { 7 | public: 8 | const Token& token; 9 | RuntimeError(const Token& token, const std::string& message); 10 | }; 11 | -------------------------------------------------------------------------------- /src/Ter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Ter { 6 | private: 7 | static void run(const std::string&); 8 | 9 | public: 10 | static void run_file(const std::string&); 11 | static void run_script(const std::string&); 12 | static void repl(); 13 | }; 14 | -------------------------------------------------------------------------------- /tests/bitwiseShift.ter: -------------------------------------------------------------------------------- 1 | output(" Shift left") 2 | out(1<<52) out("|") 3 | out(1<<55) out("|") 4 | out(1<<2) out("|") 5 | output(65500<<0) 6 | output(" Shift right") 7 | out(4503599627370496>>52) out("|") 8 | out(36028797018963968>>52) out("|") 9 | out(4>>3) out("|") 10 | output(65500>>0) -------------------------------------------------------------------------------- /src/parser/IncludeRun.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../tokenizer/Token.hpp" 4 | 5 | class IncludeRun { 6 | public: 7 | static void scanFile(std::string path); 8 | static void run(const std::string&); 9 | static std::vector tokens; 10 | static std::vector getTokens(); 11 | }; 12 | -------------------------------------------------------------------------------- /src/interpreter/BuiltinFactory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "Callable.hpp" 6 | 7 | extern std::unordered_map()>> builtinFactory; 8 | extern std::unordered_map builtinNames; 9 | -------------------------------------------------------------------------------- /tests/functions.ter: -------------------------------------------------------------------------------- 1 | set print(str){ 2 | output(str); 3 | } 4 | 5 | set add(x, y){ 6 | return x + y; 7 | } 8 | 9 | set increment(a){ 10 | return ++a; 11 | } 12 | 13 | print("My content"); // My content 14 | output(add(3, 9)); // 12 15 | 16 | auto result = increment(6); 17 | output(result); // 7 18 | 19 | output(increment(add(3,9))) //13 20 | -------------------------------------------------------------------------------- /tests/classes.ter: -------------------------------------------------------------------------------- 1 | class Animal { 2 | cat(name){ 3 | output("Cat name is: " + name); 4 | } 5 | 6 | dog(){ 7 | output("I am dog!"); 8 | } 9 | 10 | descAnimal(human){ 11 | return "Human: " + human; 12 | } 13 | } 14 | 15 | Animal().cat("Bob"); 16 | 17 | auto obj = Animal(); 18 | obj.dog(); 19 | 20 | output(obj.descAnimal("Peter")); 21 | -------------------------------------------------------------------------------- /src/tokenizer/Token.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "TokenType.hpp" 6 | 7 | class Token { 8 | public: 9 | TokenType type; 10 | std::string lexeme; 11 | std::any literal; 12 | int line; 13 | 14 | Token(TokenType type, std::string, std::any, int); 15 | bool operator <(const Token& obj) const; 16 | std::string toString(); 17 | }; 18 | -------------------------------------------------------------------------------- /src/interpreter/ArrayType.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class ArrayType { 7 | private: 8 | void insertAtIndex(int index, std::any value); 9 | 10 | public: 11 | std::vector values; 12 | void append(std::any value); 13 | bool setAtIndex(int index, std::any value); 14 | std::any getEleAt(int index); 15 | int length(); 16 | }; 17 | -------------------------------------------------------------------------------- /src/interpreter/Callable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class Interpreter; 8 | 9 | class Callable { 10 | public: 11 | virtual int arity() = 0; 12 | virtual std::any call(Interpreter &interpreter, 13 | std::vector arguments) = 0; 14 | virtual std::string toString() = 0; 15 | virtual ~Callable() = default; 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | build 34 | desk 35 | web 36 | doc.md 37 | -------------------------------------------------------------------------------- /tests/bitwiseOperators.ter: -------------------------------------------------------------------------------- 1 | auto a=0; auto b=0 2 | out(a&b) out("|") out(a|b) out("|") out(a^b) out("|") output(~a) 3 | a=-1 4 | out(a&b) out("|") out(a|b) out("|") out(a^b) out("|") output(~a) 5 | a=9007199254740991 6 | b=-9007199254740991 7 | out(a&b) out("|") out(a|b) out("|") out(a^b) out("|") output(~a) 8 | a= 6004799503160661 // 0x15555555555555 9 | b= -3002399751580330 // -0xaaaaaaaaaaaaa 10 | out(a&b) out("|") out(a|b) out("|") out(a^b) out("|") output(~a) 11 | -------------------------------------------------------------------------------- /src/utils/Debug.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "../tokenizer/Token.hpp" 4 | #include "RuntimeError.hpp" 5 | 6 | class Debug { 7 | private: 8 | static void report(int, const std::string&, const std::string&); 9 | 10 | public: 11 | inline static std::string filename; 12 | inline static bool hadError = false; 13 | inline static bool hadRuntimeError = false; 14 | static void error(int line, const std::string&); 15 | static void error(Token token, const std::string&); 16 | static void runtimeError(const RuntimeError& error); 17 | }; 18 | -------------------------------------------------------------------------------- /src/tokenizer/TokenType.hpp: -------------------------------------------------------------------------------- 1 | enum class TokenType { 2 | LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE, RIGHT_BRACKET, LEFT_BRACKET, 3 | COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR, PLUS_PLUS, MINUS_MINUS, 4 | PERCENT, AMPERSAND, CARET, VBAR, TILDE, 5 | 6 | BANG, BANG_EQUAL, 7 | EQUAL, EQUAL_EQUAL, 8 | GREATER, GREATER_EQUAL, GREATER_GREATER, 9 | LESS, LESS_EQUAL, LESS_LESS, 10 | 11 | IDENTIFIER, STRING, NUMBER, INCLUDE, 12 | 13 | AND, CLASS, ELSE, FALSE, SET, FOR, IF, NIL, OR, OUT, 14 | OUTPUT, RETURN, SUPER, THIS, TRUE, AUTO, WHILE, 15 | 16 | TER_EOF 17 | }; 18 | 19 | -------------------------------------------------------------------------------- /tests/operators.modulo.ter: -------------------------------------------------------------------------------- 1 | output(" Regular") 2 | out(7 % 3) out("|") 3 | out(7 % -3) out("|") 4 | out(-7 % 3) out("|") 5 | out(-7 % -3) out("|") 6 | output(10 % 5) 7 | output(" Limit 53 bits") 8 | out(9007199254740991 % 2) out("|") 9 | out(-9007199254740991 % 9007199254740991) out("|") 10 | out(9007199254740990 % 9007199254740991) out("|") 11 | output(9007199254740991 % 9007199254740990) 12 | output(" Floating point") 13 | out(7.5 % 3) out("|") 14 | out(-10.2 % 3) out("|") 15 | output(10 % 3.3) 16 | output(" Zero") 17 | out(7 % 0) out("|") 18 | out(-10.2 % 0) out("|") 19 | output(0 % 0) 20 | -------------------------------------------------------------------------------- /src/interpreter/Function.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Interpreter; 7 | 8 | #include "../parser/Stmt.hpp" 9 | #include "Callable.hpp" 10 | #include "Environment.hpp" 11 | 12 | class Function: public Callable { 13 | private: 14 | std::shared_ptr declaration; 15 | std::weak_ptr closure; 16 | 17 | public: 18 | Function(std::shared_ptr declaration, 19 | std::shared_ptr closure); 20 | int arity(); 21 | std::any call(Interpreter &interpreter, std::vector arguments); 22 | std::string toString(); 23 | }; 24 | -------------------------------------------------------------------------------- /src/interpreter/ArrayType.cpp: -------------------------------------------------------------------------------- 1 | #include "ArrayType.hpp" 2 | 3 | void ArrayType::append(std::any value) { 4 | values.push_back(value); 5 | } 6 | 7 | std::any ArrayType::getEleAt(int index) { 8 | return values.at(static_cast(index)); 9 | } 10 | 11 | int ArrayType::length() { 12 | return static_cast(values.size()); 13 | } 14 | 15 | bool ArrayType::setAtIndex(int index, std::any value) { 16 | if(index == length()){ 17 | values.insert(values.begin() + index, value); 18 | }else if(index < length() && index >= 0) { 19 | values[static_cast(index)] = value; 20 | }else{ 21 | return false; 22 | } 23 | return true; 24 | } 25 | -------------------------------------------------------------------------------- /src/interpreter/Instance.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Callable.hpp" 4 | #include "Interpreter.hpp" 5 | #include 6 | #include 7 | 8 | class Class; 9 | 10 | class Instance : public Callable { 11 | public: 12 | Instance(std::shared_ptr klass); 13 | 14 | std::shared_ptr klass; 15 | std::unordered_map fields; 16 | 17 | std::any get(const Token& name); 18 | void set(const Token& name, std::any value); 19 | 20 | int arity() override; 21 | std::any call(Interpreter &interpreter, std::vector arguments) override; 22 | std::string toString() override; 23 | }; 24 | -------------------------------------------------------------------------------- /src/interpreter/Class.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "Function.hpp" 7 | 8 | class Instance; 9 | 10 | class Class : public Callable{ 11 | public: 12 | Class(const std::string& name, std::unordered_map> methods); 13 | std::string name; 14 | std::unordered_map> methods; 15 | std::optional> findMethod(const std::string& l_name); 16 | 17 | int arity() override; 18 | std::any call(Interpreter &interpreter, std::vector arguments) override; 19 | std::string toString() override; 20 | }; 21 | -------------------------------------------------------------------------------- /src/utils/Helpers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Helpers { 7 | private: 8 | int size; 9 | std::vector args; 10 | Helpers() = default; 11 | 12 | public: 13 | static Helpers& get_instance() { 14 | static Helpers instance; 15 | return instance; 16 | } 17 | 18 | void set_args(const int& new_size, const std::vector& new_args) { 19 | this->size = new_size; 20 | this->args = new_args; 21 | } 22 | 23 | std::vector get_args(){ 24 | return this->args; 25 | } 26 | 27 | Helpers(const Helpers&) = delete; 28 | void operator=(const Helpers&) = delete; 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /src/interpreter/Environment.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../tokenizer/Token.hpp" 8 | 9 | class Env : public std::enable_shared_from_this { 10 | private: 11 | std::shared_ptr enclosing; 12 | std::unordered_map values; 13 | 14 | public: 15 | Env(); 16 | Env(std::shared_ptr enclosing); 17 | void define(const std::string& name, std::any value); 18 | std::any get(const Token& name); 19 | void assign(const Token& name, std::any value); 20 | std::any getAt(int distance, const std::string& name); 21 | void assignAt(int distance, Token& name, std::any value); 22 | std::shared_ptr anchestor(int distance); 23 | }; 24 | -------------------------------------------------------------------------------- /debug.ter: -------------------------------------------------------------------------------- 1 | auto compiler = "clang++ -stdlib=libc++" 2 | auto add_flags = "-O0 -fno-omit-frame-pointer -Wsign-conversion -Wnull-dereference -Wdouble-promotion -Wformat=2 -Wcast-align -Wconversion" 3 | auto sanitize = "-fsanitize=undefined -fsanitize=leak" 4 | auto flags = "-g -Wall -Werror -Wextra -Wshadow -Wpedantic -fsanitize=address" 5 | auto build = compiler + " " + add_flags + " " + sanitize + " " + " " + flags + " ./src/*.cpp" 6 | 7 | output(build) 8 | exec(build) 9 | /* 10 | 11 | Compile all: 12 | 13 | clang++ -stdlib=libc++ -O0 -fno-omit-frame-pointer -Wsign-conversion -Wnull-dereference -Wdouble-promotion -Wformat=2 -Wcast-align -Wconversion -fsanitize=undefined -fsanitize=leak -g -Wall -Werror -Wextra -Wshadow -Wpedantic -fsanitize=address $(find src -name '*.cpp') 14 | 15 | */ 16 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.25.0) 2 | 3 | set (CMAKE_CXX_STANDARD 23) 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -ffast-math") 5 | 6 | project(Terlang 7 | LANGUAGES CXX 8 | VERSION 0.0.1 9 | ) 10 | 11 | add_executable(ter src/main.cpp src/Ter.cpp) 12 | 13 | # Add sources by module 14 | function(add_sources module) 15 | file(GLOB sources "src/${module}/*.cpp") 16 | target_sources(ter PRIVATE ${sources}) 17 | endfunction() 18 | 19 | add_sources(tokenizer) 20 | add_sources(utils) 21 | add_sources(interpreter) 22 | add_sources(parser) 23 | 24 | install(TARGETS ter DESTINATION bin) 25 | 26 | add_custom_target("uninstall" COMMENT "Uninstall installed files") 27 | add_custom_command( 28 | TARGET "uninstall" 29 | POST_BUILD 30 | COMMENT "Uninstall files with install_manifest.txt" 31 | COMMAND xargs rm -vf < install_manifest.txt || echo Nothing in 32 | install_manifest.txt to be uninstalled! 33 | ) 34 | -------------------------------------------------------------------------------- /src/tokenizer/Token.cpp: -------------------------------------------------------------------------------- 1 | #include "Token.hpp" 2 | #include 3 | 4 | Token::Token(TokenType type, std::string lexeme, std::any literal, int line) : 5 | type(type), lexeme(lexeme), literal(literal), line(line) {} 6 | 7 | std::string Token::toString(){ 8 | std::stringstream ss_literal; 9 | if(literal.has_value()){ 10 | const std::type_info& type_any = literal.type(); 11 | 12 | if(type_any == typeid(std::string)){ 13 | ss_literal << std::any_cast(literal); 14 | }else if(type_any == typeid(int)){ 15 | ss_literal << std::any_cast(literal); 16 | }else if(type_any == typeid(double)){ 17 | ss_literal << std::any_cast(literal); 18 | }else{ 19 | ss_literal << "null"; 20 | } 21 | }else{ 22 | ss_literal << "[no literal]"; 23 | } 24 | return lexeme + " " + ss_literal.str(); 25 | } 26 | 27 | bool Token::operator <(const Token& obj) const{ 28 | return obj.lexeme < this->lexeme; 29 | } 30 | -------------------------------------------------------------------------------- /src/interpreter/Class.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Class.hpp" 4 | #include "Instance.hpp" 5 | #include "Interpreter.hpp" 6 | 7 | Class::Class(const std::string& name, std::unordered_map> methods) : 8 | name(name), methods(methods) {} 9 | 10 | std::any Class::call(Interpreter &interpreter, std::vector arguments){ 11 | if(arguments.size() == 0 && interpreter.global != nullptr){ 12 | std::cout << "\n"; 13 | } 14 | 15 | auto instance = std::make_shared(std::make_shared(*this)); 16 | return instance; 17 | } 18 | 19 | std::string Class::toString(){ 20 | return "name + ">"; 21 | } 22 | 23 | int Class::arity(){ 24 | return 0; 25 | } 26 | 27 | std::optional> Class::findMethod(const std::string& l_name) { 28 | auto it = methods.find(l_name); 29 | if(it != methods.end()){ 30 | return it->second; 31 | } 32 | return std::nullopt; 33 | } 34 | -------------------------------------------------------------------------------- /src/utils/Debug.cpp: -------------------------------------------------------------------------------- 1 | #include "Debug.hpp" 2 | #include 3 | 4 | void Debug::report(int line, const std::string& where, const std::string& message){ 5 | hadError = true; 6 | //std::cerr << "[" + Debug::filename + "] " << "error: line: " << line << where << ": " << message << '\n'; 7 | std::cerr << "error: line: " << line << where << ": " << message << '\n'; 8 | } 9 | 10 | void Debug::error(int line, const std::string& message){ 11 | report(line, "", message); 12 | } 13 | 14 | void Debug::error(Token token, const std::string& message){ 15 | if(token.type == TokenType::TER_EOF){ 16 | report(token.line, " at end ", message); 17 | }else{ 18 | report(token.line, " at " + token.lexeme, message); 19 | } 20 | } 21 | 22 | void Debug::runtimeError(const RuntimeError& error){ 23 | //std::cerr << "[" + Debug::filename + "] " << "[line " << error.token.line << "] Error: " << error.what() << '\n'; 24 | std::cerr << "[line " << error.token.line << "] Error: " << error.what() << '\n'; 25 | } 26 | -------------------------------------------------------------------------------- /src/interpreter/Function.cpp: -------------------------------------------------------------------------------- 1 | #include "Function.hpp" 2 | #include "Interpreter.hpp" 3 | 4 | Function::Function(std::shared_ptr declaration, 5 | std::shared_ptr closure) : declaration{std::move(declaration)}, 6 | closure{std::move(closure)} {} 7 | 8 | int Function::arity(){ 9 | return static_cast(declaration->params.size()); 10 | } 11 | 12 | std::any Function::call(Interpreter &interpreter, std::vector arguments){ 13 | auto newEnv = std::make_shared(closure.lock()); 14 | int size = static_cast(declaration->params.size()); 15 | for(int i = 0; i < size; i++){ 16 | newEnv->define(declaration->params[static_cast(i)].lexeme, arguments[static_cast(i)]); 17 | } 18 | 19 | try { 20 | interpreter.executeBlock(declaration->body, newEnv); 21 | } catch (Return returnObject) { 22 | return returnObject.value; 23 | } 24 | return nullptr; 25 | } 26 | 27 | std::string Function::toString(){ 28 | return "name.lexeme + ">"; 29 | } 30 | -------------------------------------------------------------------------------- /src/interpreter/Instance.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Instance.hpp" 4 | #include "../utils/RuntimeError.hpp" 5 | #include "Class.hpp" 6 | 7 | Instance::Instance(std::shared_ptr klass) : klass{std::move(klass)} {} 8 | 9 | std::string Instance::toString(){ 10 | return "<" + klass->name + " class instance>"; 11 | } 12 | 13 | std::any Instance::get(const Token& name){ 14 | if(fields.find(name.lexeme) != fields.end()){ 15 | return fields[name.lexeme]; 16 | } 17 | 18 | auto method = klass->findMethod(name.lexeme); 19 | if(method.has_value()){ 20 | return method.value(); 21 | } 22 | 23 | throw RuntimeError(name, "Undefinied property '" + name.lexeme + "'."); 24 | } 25 | 26 | void Instance::set(const Token& name, std::any value){ 27 | fields[name.lexeme] = std::move(value); 28 | } 29 | 30 | int Instance::arity(){ 31 | return 0; 32 | } 33 | 34 | std::any Instance::call(Interpreter &interpreter, std::vector arguments){ 35 | if(arguments.size() == 0 && interpreter.global != nullptr){ 36 | std::cout << "\n"; 37 | } 38 | return {}; 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Ter.hpp" 4 | #include "utils/Helpers.hpp" 5 | 6 | void help(const std::string& prog){ 7 | std::cerr << "Ter/Terlang v0.1.6\n\n"; 8 | std::cerr << "Usage: \n\t" << 9 | prog << " [filename].ter\n\t" << 10 | prog << " -e '