Explorar el Código

added more native types

Nicolas Winkler hace 6 años
padre
commit
db7d05b9bb

+ 2 - 8
src/Builtin.cpp

@@ -17,15 +17,9 @@ sem::NativeScope qlow::sem::generateNativeScope(Context& context)
     
     NativeScope scope{ context };
 
-    std::map<std::string, NativeType::NType> natives = {
-        { "Void",       NativeType::NType::VOID },
-        { "Boolean",    NativeType::NType::BOOLEAN },
-        { "Integer",    NativeType::NType::INTEGER },
-    };
-
-    for (auto [name, type] : natives) {
+    for (auto type : NativeType::nativeTypes) {
         Type* id = context.getNativeType(type);
-        scope.addNativeType(name, type, id);
+        scope.addNativeType(id->asString(), type, id);
     }
     
     /*std::map<std::string, NativeType::NType> natives = {

+ 1 - 11
src/CMakeLists.txt

@@ -22,7 +22,7 @@ if( NOT LLVM_FOUND )
 endif()
 
 if ( BISON_FOUND AND FLEX_FOUND )
-    BISON_TARGET(QlowParser ast/syntax.y ${CMAKE_CURRENT_BINARY_DIR}/syntax.cpp)
+    BISON_TARGET(QlowParser ast/syntax.y ${CMAKE_CURRENT_BINARY_DIR}/syntax.cpp COMPILE_FLAGS -Wno-other)
     FLEX_TARGET(QlowLexer ast/lexer.l ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp)
     ADD_FLEX_BISON_DEPENDENCY(QlowLexer QlowParser)
 else()
@@ -41,20 +41,10 @@ include_directories( ${LLVM_INCLUDE_DIRS} )
 link_directories( ${LLVM_LIBRARY_DIRS} )
 add_definitions( ${LLVM_DEFINITIONS} )
 
-if (${APPLE})
-    # hack to include libc++fs installed with homebrew
-    set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS "-L/usr/local/opt/llvm/lib")
-endif()
-
 if ( CMAKE_COMPILER_IS_GNUCC OR CMAKE_CXX_COMPILER MATCHES ".*clang" )
     target_compile_options(${PROJECT_NAME} PRIVATE 
         -Wall -Wextra -Wpedantic -pedantic -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
     )
-    if (${APPLE})
-        target_link_libraries(${PROJECT_NAME} c++fs)
-    else()
-        target_link_libraries(${PROJECT_NAME} stdc++fs)
-    endif()
     set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -DDEBUGGING")
 endif()
 if ( MSVC )

+ 7 - 5
src/CodegenVisitor.cpp

@@ -119,11 +119,13 @@ llvm::Value* ExpressionCodegenVisitor::visit(sem::BinaryOperation& binop, llvm::
 
 llvm::Value* ExpressionCodegenVisitor::visit(sem::CastExpression& cast, llvm::IRBuilder<>& builder)
 {
-    /*return builder.CreateCast(
-        llvm::Instruction::CastOps::SExt,
-        cast.expression->accept(*this, builder),
-        context.getType(cast.targetType).value().getLlvmType(builder.getContext())
-    );*/
+    if (cast.isNativeCast) {
+        return builder.CreateCast(
+            llvm::Instruction::CastOps::SExt,
+            cast.expression->accept(*this, builder),
+            cast.targetType->getLlvmType(builder.getContext())
+        );
+    }
     return nullptr;
 }
 

+ 7 - 6
src/Driver.cpp

@@ -8,10 +8,10 @@
 
 #include "Printer.h"
 #include "ErrorReporting.h"
+#include "Path.h"
 
 #include <cstdio>
 #include <set>
-#include <filesystem>
 #include <functional>
 #include <algorithm>
 
@@ -197,14 +197,14 @@ bool Driver::parseStage(void)
     this->ast = std::make_unique<ast::Ast>();
     bool errorOccurred = false;
 
-    std::set<std::filesystem::path> alreadyParsed = {};
-    std::set<std::filesystem::path> toParse = {};
+    std::set<qlow::util::Path> alreadyParsed = {};
+    std::set<qlow::util::Path> toParse = {};
 
     toParse.insert(options.infiles.begin(), options.infiles.end());
 
     while(!toParse.empty()) {
         auto filename = toParse.extract(toParse.begin()).value();
-        auto dirPath = filename.parent_path();
+        auto dirPath = filename.parentPath();
         std::FILE* file = std::fopen(filename.c_str(), "r");
 
         if (!file) {
@@ -218,9 +218,10 @@ bool Driver::parseStage(void)
             ast::Parser parser(file, filename);
             this->ast->merge(parser.parse());
             for (auto& import : parser.getImports()) {
-                auto importPath = dirPath / import->getRelativePath();
+                auto importPath = dirPath;
+                importPath.append(import->getRelativePath());
 #ifdef DEBUGGING
-                printer << "imported " << importPath << std::endl;
+                printer << "imported " << importPath.string() << std::endl;
 #endif
                 if (alreadyParsed.count(dirPath) == 0) {
                     toParse.insert(importPath);

+ 3 - 2
src/Driver.h

@@ -6,7 +6,8 @@
 #include <memory>
 #include <string>
 #include <utility>
-#include <filesystem>
+
+#include "Path.h"
 
 #include "Parser.h"
 #include "Scope.h"
@@ -47,7 +48,7 @@ class qlow::Driver
     std::unique_ptr<sem::Context> context = nullptr;
     std::unique_ptr<sem::GlobalScope> semClasses = nullptr;
 
-    std::filesystem::path tempObject = "";
+    qlow::util::Path tempObject = "";
 public:
     Driver(void) = delete;
     Driver(int argc, char** argv);

+ 8 - 1
src/ErrorReporting.h

@@ -42,9 +42,16 @@ struct qlow::CodePosition
     int last_line;
     int first_column;
     int last_column;
-    
+
     inline bool isMultiline(void) const { return first_line != last_line; }
 
+    static inline CodePosition none(void) { return CodePosition{ "", 0, 0, 0, 0 }; }
+    inline bool isNone(void)
+    {
+        return filename == "" && first_line == 0 && last_line == 0 && first_column == 0 &&
+               last_column == 0;
+    }
+
     std::string getReportFormat(void) const noexcept;
 };
 

+ 2 - 1
src/Linking.h

@@ -1,7 +1,8 @@
 #ifndef QLOW_LINKING_H_
 #define QLOW_LINKING_H_
 
-#include <filesystem>
+#include "Path.h"
+#include <vector>
 
 namespace qlow
 {

+ 4 - 4
src/ast/Ast.cpp

@@ -12,17 +12,17 @@ void Ast::merge(Ast other)
 }
 
 
-std::filesystem::path ImportDeclaration::getRelativePath(void) const
+qlow::util::Path ImportDeclaration::getRelativePath(void) const
 {
     if (imported.empty())
         return "";
-    std::filesystem::path path = imported[0];
+    qlow::util::Path path = imported[0];
 
     for (size_t i = 1; i < imported.size(); i++) {
-        path = path / imported[i];
+        path.append(imported[i]);
     }
 
-    return path.string() + ".qlw";
+    return path + ".qlw";
 }
 
 

+ 2 - 2
src/ast/Ast.h

@@ -27,10 +27,10 @@
 #include <memory>
 #include <utility>
 #include <map>
-#include <filesystem>
 
 #include "Visitor.h"
 #include "Util.h"
+#include "Path.h"
 #include "ErrorReporting.h"
 
 namespace qlow
@@ -134,7 +134,7 @@ struct qlow::ast::ImportDeclaration
     {
     }
 
-    std::filesystem::path getRelativePath(void) const;
+    qlow::util::Path getRelativePath(void) const;
 };
 
 

+ 31 - 11
src/ast/AstVisitor.cpp

@@ -205,11 +205,11 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FeatureCall& a
 
     if (target) {
         if (var) {
-            return std::make_unique<sem::FieldAccessExpression>(std::move(target), dynamic_cast<sem::Field*>(var));
+            return std::make_unique<sem::FieldAccessExpression>(std::move(target), dynamic_cast<sem::Field*>(var), ast.pos);
         }
         else if (method) {
             auto fce = std::make_unique<sem::MethodCallExpression>(
-                std::move(target), method);
+                std::move(target), method, ast.pos);
 
             if (ast.arguments.size() != method->arguments.size())
                 throw SemanticError(SemanticError::WRONG_NUMBER_OF_ARGUMENTS, ast.name, ast.pos);
@@ -245,10 +245,10 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FeatureCall& a
             auto* thisExpr = scope.getVariable("this");
             if (!thisExpr)
                 throw "no this found";
-            return std::make_unique<sem::FieldAccessExpression>(std::make_unique<sem::LocalVariableExpression>(thisExpr), field);
+            return std::make_unique<sem::FieldAccessExpression>(std::make_unique<sem::LocalVariableExpression>(thisExpr, CodePosition::none()), field, ast.pos);
         }
         else {
-            return std::make_unique<sem::LocalVariableExpression>(var);
+            return std::make_unique<sem::LocalVariableExpression>(var, ast.pos);
         }
     }
     else if (method) {
@@ -258,9 +258,9 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FeatureCall& a
             auto* thisVar = scope.getVariable("this");
             if (!thisVar)
                 throw SemanticError(SemanticError::UNKNOWN_TYPE, "no this found", ast.pos);
-            thisExpr = std::make_unique<sem::LocalVariableExpression>(thisVar);
+            thisExpr = std::make_unique<sem::LocalVariableExpression>(thisVar, CodePosition::none());
         }
-        auto fce = std::make_unique<sem::MethodCallExpression>(std::move(thisExpr), method);
+        auto fce = std::make_unique<sem::MethodCallExpression>(std::move(thisExpr), method, ast.pos);
         for (auto& arg : ast.arguments) {
             auto argument = arg->accept(*this, scope);
             if (dynamic_cast<sem::Expression*>(argument.get())) {
@@ -364,14 +364,14 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(
 
 std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::IntConst& ast, sem::Scope& scope)
 {
-    return std::make_unique<sem::IntConst>(scope.getContext(), ast.value);
+    return std::make_unique<sem::IntConst>(scope.getContext(), ast.value, ast.pos);
 }
 
 
 std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::UnaryOperation& ast, sem::Scope& scope)
 {
     auto argument = unique_dynamic_cast<sem::Expression>(ast.expr->accept(*this, scope));
-    auto ret = std::make_unique<sem::UnaryOperation>(scope.getContext(), argument->type);
+    auto ret = std::make_unique<sem::UnaryOperation>(scope.getContext(), argument->type, ast.pos);
             // TODO not a feasible assumption
     ret->opString = ast.opString;
     ret->side = ast.side;
@@ -419,7 +419,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::BinaryOperatio
 
 std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::NewExpression& ast, sem::Scope& scope)
 {
-    auto ret = std::make_unique<sem::NewExpression>(scope.getContext(), scope.getType(ast.type.get()));
+    auto ret = std::make_unique<sem::NewExpression>(scope.getContext(), scope.getType(ast.type.get()), ast.pos);
     auto* classType = ret->type->getClass();
     if (classType != nullptr && classType->isReferenceType) {
         return ret;
@@ -432,7 +432,7 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::NewExpression&
 
 std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::NewArrayExpression& ast, sem::Scope& scope)
 {
-    auto ret = std::make_unique<sem::NewArrayExpression>(scope.getContext(), scope.getType(ast.type.get()));
+    auto ret = std::make_unique<sem::NewArrayExpression>(scope.getContext(), scope.getType(ast.type.get()), ast.pos);
     return ret;
 }
 
@@ -442,6 +442,26 @@ std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::CastExpression
     auto expr = unique_dynamic_cast<sem::Expression>(ast.expression->accept(*this, scope));
     auto type = scope.getType(ast.targetType.get());
     return std::make_unique<sem::CastExpression>(
-        std::move(expr), type, &ast);
+        std::move(expr), type, &ast, false, ast.pos);
 }
 
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::createImplicitCast(
+        std::unique_ptr<sem::Expression> expr, sem::Type* targetType, sem::Scope& scope)
+{
+    auto* exprType = expr->type;
+    if (/*exprType->isImplicitelyCastableTo(targetType)*/true) {
+        return std::make_unique<sem::CastExpression>(
+            std::move(expr), targetType, nullptr, true, expr->pos);
+    }
+    else {
+        // TODO add position to error
+        throw qlow::SemanticError(SemanticError::TYPE_MISMATCH,
+                "cannot cast from '" + exprType->asString() + "' to '" + targetType->asString() + "'",
+                expr->pos);
+    }
+}
+
+
+
+

+ 3 - 0
src/ast/AstVisitor.h

@@ -5,6 +5,7 @@
 #include "Ast.h"
 #include "Semantic.h"
 #include "Builtin.h"
+#include "Type.h"
 #include "Scope.h"
 
 
@@ -79,6 +80,8 @@ public:
     ReturnType visit(ast::NewExpression& ast, sem::Scope& scope) override;
     ReturnType visit(ast::NewArrayExpression& ast, sem::Scope& scope) override;
     ReturnType visit(ast::CastExpression& ast, sem::Scope& scope) override;
+
+    ReturnType createImplicitCast(std::unique_ptr<sem::Expression>, sem::Type* targetType, sem::Scope& scope);
 };
 
 

+ 4 - 4
src/ast/Parser.h

@@ -3,7 +3,7 @@
 
 #include <cstdio>
 #include <string>
-#include <filesystem>
+#include "Path.h"
 #include "Ast.h"
 
 namespace qlow
@@ -17,10 +17,10 @@ namespace qlow
 class qlow::ast::Parser
 {
     FILE* stream;
-    std::filesystem::path filename;
+    qlow::util::Path filename;
     std::vector<std::unique_ptr<ImportDeclaration>> imports;
 public:
-    inline Parser(FILE* stream, std::filesystem::path filename) :
+    inline Parser(FILE* stream, qlow::util::Path filename) :
         stream{ stream }, filename{ std::move(filename) } {}
     
     Ast parse(void);
@@ -28,7 +28,7 @@ public:
     void addImports(std::vector<std::unique_ptr<ImportDeclaration>> toAdd);
     const std::vector<std::unique_ptr<ImportDeclaration>>& getImports(void) const;
 
-    inline std::string getFilename(void) const { return filename.string(); }
+    inline std::string getFilename(void) const { return filename; }
 };
 
 #endif // QLOW_AST_PARSER_H

+ 2 - 0
src/ast/syntax.y

@@ -218,6 +218,8 @@ while (0)
 
 %start topLevel
 
+%expect 65
+
 %%
 
 /* list of class definitions */

+ 2 - 1
src/main.cpp

@@ -10,6 +10,7 @@
 #include "CodeGeneration.h"
 
 #include "Driver.h"
+#include "Path.h"
 
 int main(int argc, char** argv) try
 {
@@ -28,7 +29,7 @@ int main(int argc, char** argv) try
 catch (float f) {
     std::cerr << "uncaught float" << std::endl;
 }
-catch (std::bad_alloc ba) {
+catch (const std::bad_alloc& ba) {
     std::cerr << "out of memory" << std::endl;
 }
 /*catch(...) {

+ 0 - 21
src/sem/CodeGeneration.cpp

@@ -48,27 +48,6 @@ std::unique_ptr<llvm::Module> generateModule(sem::GlobalScope& semantic)
 
     // create llvm structs
     // TODO implement detection of circles
-    /*
-    for (const auto& [name, cl] : semantic.getClasses()) {
-        llvm::StructType* st;
-        std::vector<llvm::Type*> fields;
-#ifdef DEBUGGING
-        printf("creating llvm struct for %s\n", name.c_str());
-#endif
-        int llvmStructIndex = 0;
-        
-        // TODO: rewrite
-        /*for (auto& [name, field] : cl->fields) {
-            field->llvmStructIndex = llvmStructIndex;
-            fields.push_back(field->type->getLlvmType(context));
-            if (fields[fields.size() - 1] == nullptr)
-                throw "internal error: possible circular dependency";
-            
-            llvmStructIndex++;
-        }*//*
-        st = llvm::StructType::create(context, fields, name);
-        cl->llvmType = st;
-    }*/
     semantic.getContext().createLlvmTypes(context);
     
     llvm::AttrBuilder ab;

+ 2 - 2
src/sem/CodeGeneration.h

@@ -27,7 +27,7 @@ class qlow::gen::FunctionGenerator
 {
     const sem::Method& method;
     llvm::Module* module;
-    llvm::AttributeSet& attributes;
+    //llvm::AttributeSet& attributes;
 
     std::stack<llvm::BasicBlock*> basicBlocks;
 
@@ -42,7 +42,7 @@ public:
         llvm::AttributeSet& attributes) :
         method{ m },
         module{ module },
-        attributes{ attributes },
+        //attributes{ attributes },
         expressionVisitor{ *this },
         builder{ module->getContext() }
     {

+ 32 - 23
src/sem/Semantic.h

@@ -300,10 +300,12 @@ struct qlow::sem::Expression :
                      qlow::LValueVisitor>
 {
     Type* type;
+    CodePosition pos;
     
-    inline Expression(Context& context, Type* type) :
+    inline Expression(Context& context, Type* type, const CodePosition& pos) :
         SemanticObject{ context },
-        type{ type }
+        type{ type },
+        pos{ pos }
     {
     }
     
@@ -318,8 +320,8 @@ struct qlow::sem::Operation : public Expression
 {
     std::string opString;
     
-    inline Operation(Context& context, Type* type) :
-        Expression{ context, type }
+    inline Operation(Context& context, Type* type, const CodePosition& pos) :
+        Expression{ context, type, pos }
     {
     }
 };
@@ -329,8 +331,8 @@ struct qlow::sem::LocalVariableExpression : public Expression
 {
     Variable* var;
     
-    inline LocalVariableExpression(Variable* var) :
-        Expression{ var->context, var->type },
+    inline LocalVariableExpression(Variable* var, const CodePosition& pos) :
+        Expression{ var->context, var->type, pos },
         var{ var }
     {
     }
@@ -348,7 +350,7 @@ struct qlow::sem::AddressExpression : public Expression
     std::unique_ptr<sem::Expression> target;
     
     inline AddressExpression(std::unique_ptr<sem::Expression> target) :
-        Expression{ target->context, nullptr /*context.createPointerType(target->type)*/ },
+        Expression{ target->context, nullptr /*context.createPointerType(target->type)*/, CodePosition{} },
         target{ std::move(target) }
     {
     }
@@ -368,7 +370,7 @@ struct qlow::sem::BinaryOperation : public Operation
     
     inline BinaryOperation(Context& context,
             Type* type, ast::BinaryOperation* astNode) :
-        Operation{ context, type },
+        Operation{ context, type , astNode->pos},
         astNode{ astNode }
     {
     }
@@ -385,14 +387,21 @@ struct qlow::sem::CastExpression : public Expression
     Type* targetType;
     
     ast::CastExpression* astNode;
+
+    bool isImplicit;
+    bool isNativeCast;
     
     inline CastExpression(std::unique_ptr<Expression> expression,
                           Type* type,
-                          ast::CastExpression* astNode) :
-        Expression{ expression->context, type },
+                          ast::CastExpression* astNode,
+                          bool isNative,
+                          const CodePosition& pos) :
+        Expression{ expression->context, type, pos },
         expression{ std::move(expression) },
         targetType{ type },
-        astNode{ astNode }
+        astNode{ astNode },
+        isImplicit{ astNode == nullptr },
+        isNativeCast{ isNative }
     {
     }
     
@@ -404,8 +413,8 @@ struct qlow::sem::CastExpression : public Expression
 
 struct qlow::sem::NewExpression : public Expression
 {
-    inline NewExpression(Context& context, Type* type) :
-        Expression{ context, type }
+    inline NewExpression(Context& context, Type* type, const CodePosition& pos) :
+        Expression{ context, type, pos }
     {
     }
     
@@ -419,8 +428,8 @@ struct qlow::sem::NewArrayExpression : public Expression
     Type* elementType;
     std::unique_ptr<Expression> length;
     
-    inline NewArrayExpression(Context& context, Type* elementType) :
-        Expression{ context, context.getArrayType(elementType) },
+    inline NewArrayExpression(Context& context, Type* elementType, const CodePosition& pos) :
+        Expression{ context, context.getArrayType(elementType), pos },
         elementType{ elementType }
     {
     }
@@ -435,8 +444,8 @@ struct qlow::sem::UnaryOperation : public Operation
     qlow::ast::UnaryOperation::Side side;
     std::unique_ptr<Expression> arg;
     
-    inline UnaryOperation(Context& context, Type* type) :
-        Operation{ context, type }
+    inline UnaryOperation(Context& context, Type* type, const CodePosition& pos) :
+        Operation{ context, type, pos }
     {
     }
     
@@ -452,8 +461,8 @@ struct qlow::sem::MethodCallExpression : public Expression
     OwningList<Expression> arguments;
     
     inline MethodCallExpression(std::unique_ptr<Expression> target,
-                                Method* callee) :
-        Expression{ callee->context, callee->returnType },
+                                Method* callee, const CodePosition& pos) :
+        Expression{ callee->context, callee->returnType, pos },
         callee{ callee },
         target{ std::move(target) }
     {
@@ -472,8 +481,8 @@ struct qlow::sem::FieldAccessExpression : public Expression
     //OwningList<Expression> arguments;
     
     inline FieldAccessExpression(std::unique_ptr<Expression> target,
-                                 Field* accessed ) :
-        Expression{ target->context, accessed->type },
+                                 Field* accessed, const CodePosition& pos) :
+        Expression{ target->context, accessed->type, pos },
         accessed{ accessed },
         target{ std::move(target) }
     {
@@ -492,8 +501,8 @@ struct qlow::sem::IntConst : public Expression
 {
     unsigned long long value;
 
-    inline IntConst(Context& context, unsigned long long value) :
-        Expression{ context, context.getNativeType(NativeType::NType::INTEGER) },
+    inline IntConst(Context& context, unsigned long long value, const CodePosition& pos) :
+        Expression{ context, context.getNativeType(NativeType::NType::INTEGER), pos },
         value{ value }
     {
     }

+ 45 - 0
src/sem/Type.cpp

@@ -8,6 +8,7 @@
 #include <llvm/IR/Type.h>
 
 #include <map>
+#include <climits>
 
 using qlow::sem::Type;
 using qlow::sem::NativeType;
@@ -81,6 +82,17 @@ bool Type::isVoid(void) const
 }
 
 
+const std::vector<NativeType::NType> NativeType::nativeTypes = {
+    NType::VOID,
+    NType::INTEGER,
+    NType::BOOLEAN,
+    NType::C_CHAR,
+    NType::C_SHORT,
+    NType::C_INT,
+    NType::C_LONG,
+};
+
+
 bool NativeType::equals(const Type& other) const
 {
     return other.isNativeType() && static_cast<const NativeType&>(other).type == type;
@@ -105,6 +117,10 @@ std::string NativeType::asString(void) const
         { NType::VOID, "Void" },
         { NType::INTEGER, "Integer" },
         { NType::BOOLEAN, "Boolean" },
+        { NType::C_CHAR, "CChar" },
+        { NType::C_SHORT, "CShort" },
+        { NType::C_INT, "CInt" },
+        { NType::C_LONG, "CLong" },
     };
     return names.at(type);
 }
@@ -134,6 +150,35 @@ void NativeType::createLlvmTypeDecl(llvm::LLVMContext& ctxt)
     case NType::BOOLEAN:
         llvmType = llvm::Type::getInt1Ty(ctxt);
         break;
+#if CHAR_BIT == 8 && USHRT_MAX == 65535 && UINT_MAX == 4294967295
+    case NType::C_CHAR:
+        llvmType = llvm::Type::getInt8Ty(ctxt);
+        break;
+    case NType::C_SHORT:
+        llvmType = llvm::Type::getInt16Ty(ctxt);
+        break;
+    case NType::C_INT:
+        llvmType = llvm::Type::getInt32Ty(ctxt);
+        break;
+#else
+#error unknown C abi
+#endif
+
+#if ULONG_MAX == 4294967295
+    case NType::C_LONG:
+        llvmType = llvm::Type::getInt32Ty(ctxt);
+        break;
+#elif ULONG_MAX == 18446744073709551615ULL
+    case NType::C_LONG:
+        llvmType = llvm::Type::getInt64Ty(ctxt);
+        break;
+#else
+#error unknown C abi
+#endif
+    default:
+        throw qlow::SemanticError(SemanticError::UNKNOWN_TYPE,
+                "invalid native type '" + asString() + "'",
+                qlow::CodePosition::none());
     }
 }
 

+ 6 - 0
src/sem/Type.h

@@ -1,6 +1,7 @@
 #ifndef QLOW_SEM_TYPE_H
 #define QLOW_SEM_TYPE_H
 
+#include <vector>
 #include <variant>
 #include <memory>
 #include <string>
@@ -111,7 +112,12 @@ public:
         VOID,
         INTEGER,
         BOOLEAN,
+        C_CHAR,
+        C_SHORT,
+        C_INT,
+        C_LONG,
     };
+    static const std::vector<NType> nativeTypes;
 protected:
 
     NType type;

+ 1 - 1
src/test.qlw

@@ -17,7 +17,7 @@ end
 */
 
 main: Integer do
-    count: Integer
+    count: CInt
     count := 0
     while count != 20 do
         printint(fast_fibonacci(count))

+ 44 - 1
src/util/Path.cpp

@@ -17,14 +17,57 @@ void Path::append(const Path& other)
 }
 
 
+Path Path::parentPath(void) const
+{
+    Path parent = *this;
+
+    if (parent.path == dirSeparator)
+        return parent;
+
+    if (parent.endsWithSeparator()) {
+        parent.path.pop_back();
+        return parent;
+    }
+
+    while (!parent.endsWithSeparator()) {
+        parent.path.pop_back();
+    }
+
+    if (parent.path.size() > dirSeparator.size() && parent.endsWithSeparator())
+        parent.path.pop_back();
+
+    return parent;
+}
+
+
+Path Path::operator+(const std::string& op) const
+{
+    Path r = *this;
+    r.path += op;
+    return r;
+}
+
+
 Path::operator const std::string&(void) const
 {
     return path;
 }
 
 
+const std::string& Path::string(void) const
+{
+    return path;
+}
+
+
+const char* Path::c_str(void) const
+{
+    return path.c_str();
+}
+
+
 bool Path::endsWithSeparator(void) const
 {
-    return path.size() > dirSeparator.size() &&
+    return path.size() >= dirSeparator.size() &&
         std::equal(dirSeparator.rbegin(), dirSeparator.rend(), path.rbegin());
 }

+ 14 - 0
src/util/Path.h

@@ -23,8 +23,22 @@ public:
     {
     }
 
+    inline Path(const char* path) :
+        path{ path }
+    {
+    }
+
     void append(const Path& other);
+    Path parentPath(void) const;
+
+    Path operator +(const std::string& op) const;
+
+    /// for compatibilty with std::map
+    inline bool operator < (const Path& other) const { return path < other.path; }
+
     operator const std::string&(void) const;
+    const std::string& string(void) const;
+    const char* c_str(void) const;
     
 private:
     bool endsWithSeparator(void) const;