commit 9655c056972133764131b105a9cd11273d509826 Author: Ludwig Lehnert Date: Sat Feb 24 21:34:06 2024 +0100 added project files diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d163863 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0a51fc0 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,76 @@ + +{ + "[yacc]": { + "problems.decorations.enabled": false, + }, + "files.associations": { + "*.embeddedhtml": "html", + "any": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "list": "cpp", + "map": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "format": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "semaphore": "cpp", + "span": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stdfloat": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp", + "valarray": "cpp", + "variant": "cpp" + }, +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..6b8de49 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# plsm +Mainly functional general purpose programming language \ No newline at end of file diff --git a/compiler/.gitignore b/compiler/.gitignore new file mode 100644 index 0000000..5c64952 --- /dev/null +++ b/compiler/.gitignore @@ -0,0 +1 @@ +*.gen.* diff --git a/compiler/CMakeLists.txt b/compiler/CMakeLists.txt new file mode 100644 index 0000000..b18caf0 --- /dev/null +++ b/compiler/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.25) + +project(plasmatum) + +set(CMAKE_CXX_STANDARD 23) +set(SOURCE_DIR ${CMAKE_SOURCE_DIR}/src) +set(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include) + +find_package(FLEX REQUIRED) +find_package(BISON REQUIRED) + +BISON_TARGET(parser + ${CMAKE_SOURCE_DIR}/parser.yy + ${SOURCE_DIR}/parser.gen.cpp + DEFINES_FILE ${INCLUDE_DIR}/parser.gen.h) + +FLEX_TARGET(lexer + ${CMAKE_SOURCE_DIR}/lexer.ll + ${SOURCE_DIR}/lexer.gen.cpp) + +ADD_FLEX_BISON_DEPENDENCY(lexer parser) + +file(GLOB_RECURSE sources ${SOURCE_DIR}/*.cpp) +set(sources ${sources} ${FLEX_lexer_OUTPUTS}) +set(sources ${sources} ${BISON_parser_OUTPUT_SOURCE}) + +include_directories(${CMAKE_SOURCE_DIR}/include) +add_executable(plsm ${sources}) diff --git a/compiler/include/AST.h b/compiler/include/AST.h new file mode 100644 index 0000000..9b46c36 --- /dev/null +++ b/compiler/include/AST.h @@ -0,0 +1,49 @@ +#pragma once + +#include + +class Expr; + +class ASTNode +{ +}; + +class Stmt : public ASTNode +{ +}; + +class Decl : public Stmt +{ +public: + Decl(const std::string &identifier, const Expr *value) + : identifier(identifier), value(value) {} + + const std::string identifier; + const Expr *value; +}; + +class Expr : public ASTNode +{ +}; + +class IntValue : public Expr +{ +public: + const long value; + IntValue(const long value) : value(value) {} +}; + +class FloatValue : public Expr +{ +public: + const double value; + FloatValue(const double value) : value(value) {} +}; + +class Function : public Expr +{ +}; + +class List : public Expr +{ +}; diff --git a/compiler/include/ASTVisitor.h b/compiler/include/ASTVisitor.h new file mode 100644 index 0000000..870f272 --- /dev/null +++ b/compiler/include/ASTVisitor.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "AST.h" + +template +class ASTVisitor +{ + virtual T visit(const ASTNode *node) + { + if (IntValue *cnode = dynamic_cast(node)) + return visitIntValue(cnode); + else if (FloatValue *cnode = dynamic_cast(node)) + return visitFloatValue(cnode); + + throw std::logic_error("not implemented"); + } + + virtual T visitIntValue(const IntValue *node); + virtual T visitFloatValue(const IntValue *node); +}; diff --git a/compiler/include/ParserDriver.h b/compiler/include/ParserDriver.h new file mode 100644 index 0000000..86ca5b6 --- /dev/null +++ b/compiler/include/ParserDriver.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include "AST.h" +#include "parser.gen.h" + +class ParserDriver +{ +public: + ParserDriver() {} + + int parse(const std::string &input); + + void startLexer(); + void stopLexer(); + + std::string file; + yy::location location; +}; + +#define YY_DECL yy::parser::symbol_type yylex(ParserDriver &driver) +YY_DECL; diff --git a/compiler/lexer.ll b/compiler/lexer.ll new file mode 100644 index 0000000..1f32687 --- /dev/null +++ b/compiler/lexer.ll @@ -0,0 +1,57 @@ +%{ +#include "parser.gen.h" +#include "ParserDriver.h" + +#define yyterminate() yy::parser::make_END(yy::location()) + +#define _token(token) yy::parser::make_##token(driver.location) +%} + +%option noyywrap nounput noinput batch debug + +digit [0-9] +bindigit [0-1] +octdigit [0-7] +hexdigit [0-9a-fA-F] + +letter [a-zA-Z] + +whitespace [ \n\t\r\v]+ + +%% + +"0b"{bindigit}+ { return yy::parser::make_INT(std::strtol(yytext, NULL, 2), driver.location); } +"0o"{octdigit}+ { return yy::parser::make_INT(std::strtol(yytext, NULL, 8), driver.location); } +"0x"{hexdigit}+ { return yy::parser::make_INT(std::strtol(yytext, NULL, 16), driver.location); } +{digit}+ { return yy::parser::make_INT(std::strtol(yytext, NULL, 10), driver.location); } + +{digit}*"."{digit}+ { return yy::parser::make_FLOAT(std::strtod(yytext, NULL), driver.location); } + +// TODO: operator '==' won't work this way +"->" { return _token(R_ARR); } +"<-" { return _token(L_ARR); } +";" { return _token(SEMI); } +"=" { return _token(EQUALS); } + +("+"|"-"|"*"|"/"|"%"|"!"|"&"|"$"|"ยง"|"|"|"="|"<"|">"|"?"|"~"|"#"|":"|"^"|"\\")+ { return _token(OPERATOR); } + + +"fn" { return _token(FN); } +"unop" { return _token(UNOP); } +"binop" { return _token(BINOP); } +"val" { return _token(VAL); } +"import" { return _token(IMPORT); } +"declare" { return _token(DECLARE); } + + +{letter}({digit}|{letter})* { return yy::parser::make_IDENTIFIER(yytext, driver.location); } + +{whitespace} { ; } + +%% + +void ParserDriver::startLexer() { + yy_scan_string(this->file.data()); +} + +void ParserDriver::stopLexer() {} diff --git a/compiler/parser.yy b/compiler/parser.yy new file mode 100644 index 0000000..223783e --- /dev/null +++ b/compiler/parser.yy @@ -0,0 +1,106 @@ +%require "3.8" +%language "c++" + +%header + +%define api.token.raw +%define api.value.type variant +%define api.token.constructor +%define api.token.prefix {TOK_} + +%define parse.assert +%define parse.trace +%define parse.error detailed +%define parse.lac full + +%locations +%define api.location.file "../include/location.gen.h" +%define api.location.include {"location.gen.h"} + +%code requires { +#include "AST.h" +class ParserDriver; +} + +%lex-param { ParserDriver &driver } +%parse-param { ParserDriver &driver } + +%code { +#include "ParserDriver.h" +} + +%token INT "integer literal" +%token FLOAT "float literal" + +%token OPERATOR "operator"; +%token IDENTIFIER "identifier" + +%token L_ARR "<-" +%token R_ARR "->" +%token EQUALS "=" +%token SEMI ";" + +%token + FN "fn" + UNOP "unop" + BINOP "binop" + VAL "val" + IMPORT "import" + DECLARE "declare" +; + +%token END 0 "end of file" + +%type > stmts; +%type stmt; +%type decl; +%type expr; +%type literal; + +%type operator; +%type identifier; +%type keyword; + +%% + +module: stmts; + +stmts: stmt { $$ = std::vector(); $$.push_back($1); } + | stmts stmt { $1.push_back($2); $$ = std::move($1); } + ; + +stmt: decl { $$ = $1; } + ; + +decl: VAL identifier "=" expr ";" { $$ = new Decl($2, $4); } + ; + +expr: literal { $$ = $1; } + ; + +literal: INT { $$ = new IntValue($1); } + | FLOAT { $$ = new FloatValue($1); } + ; + +operator: L_ARR { $$ = $1; } + | R_ARR { $$ = $1; } + | EQUALS { $$ = $1; } + | OPERATOR { $$ = $1; } + ; + +identifier: keyword { $$ = $1; } + | IDENTIFIER { $$ = $1; } + ; + +keyword: FN { $$ = $1; } + | UNOP { $$ = $1; } + | BINOP { $$ = $1; } + | IMPORT { $$ = $1; } + | DECLARE { $$ = $1; } + ; + +%% + +void yy::parser::error (const location_type& l, const std::string& m) { + std::cerr << l << ": " << m << '\n'; +} diff --git a/compiler/src/ParserDriver.cpp b/compiler/src/ParserDriver.cpp new file mode 100644 index 0000000..ecefb55 --- /dev/null +++ b/compiler/src/ParserDriver.cpp @@ -0,0 +1,14 @@ +#include "ParserDriver.h" + +int ParserDriver::parse(const std::string &input) +{ + file = input; + location.initialize(&file); + + startLexer(); + yy::parser parse(*this); + int res = parse(); + stopLexer(); + + return res; +} diff --git a/compiler/src/main.cpp b/compiler/src/main.cpp new file mode 100644 index 0000000..88cc9d6 --- /dev/null +++ b/compiler/src/main.cpp @@ -0,0 +1,5 @@ +#include + +int main() +{ +} diff --git a/examples/stdlib.plsm b/examples/stdlib.plsm new file mode 100644 index 0000000..b9b2996 --- /dev/null +++ b/examples/stdlib.plsm @@ -0,0 +1,30 @@ +type Bool = class { + declare unop ! -> Bool; + + declare binop &&(b Bool) -> Bool; + declare binop ||(b Bool) -> Bool; +}; + +type Int = class { + declare unop + -> Int; + declare unop - -> Int; + + declare binop ==(b Int) -> Bool; + declare binop !=(b Int) -> Bool; + declare binop >(b Int) -> Bool; + declare binop <(b Int) -> Bool; + declare binop >=(b Int) -> Bool; + declare binop <=(b Int) -> Bool; + + declare binop +(b Int) -> Int; + declare binop -(b Int) -> Int; + declare binop *(b Int) -> Int; + declare binop /(b Int) -> Int; + declare binop %(b Int) -> Int; + + declare fn str() -> String; +}; + +type String = class (data List[Char]) { + +} diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..65be2a5 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.25) + +project(libplsm C) + +set(CMAKE_C_STANDARD 11) + +file(GLOB_RECURSE sources ${CMAKE_SOURCE_DIR}/src/*.c) +include_directories(${CMAKE_SOURCE_DIR}/include) +add_library(libplsm SHARED ${sources}) diff --git a/lib/include/function.h b/lib/include/function.h new file mode 100644 index 0000000..d93157f --- /dev/null +++ b/lib/include/function.h @@ -0,0 +1,6 @@ +#pragma once + +typedef struct +{ + +} function_t; diff --git a/lib/include/list.h b/lib/include/list.h new file mode 100644 index 0000000..3b7fe1f --- /dev/null +++ b/lib/include/list.h @@ -0,0 +1,16 @@ +#pragma once + +#include "type.h" +#include "value.h" + +typedef struct +{ + value_t *value; + list_node_t *next; +} list_node_t; + +typedef struct +{ + type_t *type; + list_node_t *head; +} list_t; diff --git a/lib/include/macros.h b/lib/include/macros.h new file mode 100644 index 0000000..a68d12e --- /dev/null +++ b/lib/include/macros.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#define DIE \ + { \ + exit(EXIT_FAILURE); \ + } + +#define DIE_ERRNO(action) \ + { \ + perror(action); \ + DIE; \ + } + +#define MODINIT(module) void plsmmod_##module##_init() + +#define LIB(name) plsmlib_##name diff --git a/lib/include/type.h b/lib/include/type.h new file mode 100644 index 0000000..477b6f4 --- /dev/null +++ b/lib/include/type.h @@ -0,0 +1,14 @@ +#pragma once + +#include "macros.h" + +typedef struct type_t type_t; + +typedef struct type_t +{ + type_t *base; + int opaque; + char *name; +} type_t; + +type_t *LIB(makeType)(type_t *base, int opaque, char *name); diff --git a/lib/include/value.h b/lib/include/value.h new file mode 100644 index 0000000..23da0ac --- /dev/null +++ b/lib/include/value.h @@ -0,0 +1,9 @@ +#pragma once + +#include "type.h" + +typedef struct +{ + type_t *type; + void *value; +} value_t; diff --git a/lib/src/function.c b/lib/src/function.c new file mode 100644 index 0000000..d4b693e --- /dev/null +++ b/lib/src/function.c @@ -0,0 +1 @@ +#include "function.h" diff --git a/lib/src/module.c b/lib/src/module.c new file mode 100644 index 0000000..8ba2c14 --- /dev/null +++ b/lib/src/module.c @@ -0,0 +1,5 @@ +#include "macros.h" + +MODINIT(stdlib) +{ +} diff --git a/lib/src/type.c b/lib/src/type.c new file mode 100644 index 0000000..db03230 --- /dev/null +++ b/lib/src/type.c @@ -0,0 +1,16 @@ +#include "type.h" + +#include + +type_t *LIB(makeType)(type_t *base, int opaque, char *name) +{ + type_t *type = malloc(sizeof(type_t)); + if (!type) + DIE_ERRNO("malloc"); + + type->base = base; + type->opaque = opaque; + type->name = name; + + return type; +} diff --git a/lib/src/types.c b/lib/src/types.c new file mode 100644 index 0000000..d199ac6 --- /dev/null +++ b/lib/src/types.c @@ -0,0 +1,12 @@ +#include "type.h" + +type_t *LIB(typeAny), *LIB(typeNum), *LIB(typeInt), *LIB(typeFloat); + +void LIB(initTypes)() +{ + LIB(typeAny) = LIB(makeType)(NULL, "Any"); + + LIB(typeNum) = LIB(makeType)(LIB(typeAny), "Num"); + LIB(typeInt) = LIB(makeType)(LIB(typeNum), "Int"); + LIB(typeFloat) = LIB(makeType)(LIB(typeNum), "Float"); +}