Nicolas Winkler 6 gadi atpakaļ
vecāks
revīzija
82c4801e1d
6 mainītis faili ar 1137 papildinājumiem un 0 dzēšanām
  1. 62 0
      src/ast/Ast.cpp
  2. 569 0
      src/ast/Ast.h
  3. BIN
      src/ast/Ast.o
  4. 419 0
      src/ast/AstVisitor.cpp
  5. 87 0
      src/ast/AstVisitor.h
  6. BIN
      src/ast/AstVisitor.o

+ 62 - 0
src/ast/Ast.cpp

@@ -0,0 +1,62 @@
+#include "Ast.h"
+#include "AstVisitor.h"
+#include "Semantic.h"
+
+#include <cstdlib>
+
+using namespace qlow::ast;
+
+
+AstObject::~AstObject(void)
+{
+}
+
+
+#define ACCEPT_DEFINITION(ClassName, Visitor) \
+std::unique_ptr<qlow::sem::SemanticObject> ClassName::accept(Visitor& v, sem::Scope& scope) \
+{ \
+    return v.visit(*this, scope); \
+}
+
+ACCEPT_DEFINITION(Class, StructureVisitor)
+ACCEPT_DEFINITION(FeatureDeclaration, StructureVisitor)
+ACCEPT_DEFINITION(FieldDeclaration, StructureVisitor)
+ACCEPT_DEFINITION(MethodDefinition, StructureVisitor)
+ACCEPT_DEFINITION(VariableDeclaration, StructureVisitor)
+
+ACCEPT_DEFINITION(Statement, StructureVisitor)
+ACCEPT_DEFINITION(DoEndBlock, StructureVisitor)
+ACCEPT_DEFINITION(IfElseBlock, StructureVisitor)
+ACCEPT_DEFINITION(WhileBlock, StructureVisitor)
+ACCEPT_DEFINITION(Expression, StructureVisitor)
+ACCEPT_DEFINITION(FeatureCall, StructureVisitor)
+ACCEPT_DEFINITION(AssignmentStatement, StructureVisitor)
+ACCEPT_DEFINITION(ReturnStatement, StructureVisitor)
+ACCEPT_DEFINITION(LocalVariableStatement, StructureVisitor)
+ACCEPT_DEFINITION(AddressExpression, StructureVisitor)
+ACCEPT_DEFINITION(IntConst, StructureVisitor)
+ACCEPT_DEFINITION(UnaryOperation, StructureVisitor)
+ACCEPT_DEFINITION(BinaryOperation, StructureVisitor)
+ACCEPT_DEFINITION(NewArrayExpression, StructureVisitor)
+ACCEPT_DEFINITION(CastExpression, StructureVisitor)
+
+
+Statement::~Statement(void)
+{
+}
+
+
+qlow::ast::IntConst::IntConst(std::string&& val, const qlow::CodePosition& p) :
+    AstObject{ p },
+    Expression{ p },
+    value{ strtoull(val.c_str(), nullptr, 0) }
+{
+}
+
+
+
+
+
+
+
+

+ 569 - 0
src/ast/Ast.h

@@ -0,0 +1,569 @@
+// =============================================================================
+//
+// This file is part of the qlow compiler.
+//
+// Copyright (C) 2014-2015 Nicolas Winkler
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// =============================================================================
+
+#ifndef QLOW_AST_H
+#define QLOW_AST_H
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <utility>
+#include <map>
+
+#include "Visitor.h"
+#include "Util.h"
+#include "ErrorReporting.h"
+
+namespace qlow
+{
+    struct CodePosition;
+    
+    class StructureVisitor;
+    namespace ast
+    {
+        // base class
+        struct AstObject;
+
+        struct Class;
+
+        struct Type;
+        struct ClassType;
+        struct ArrayType;
+        struct PointerType;
+        
+        struct FeatureDeclaration;
+
+        struct FieldDeclaration;
+        struct MethodDefinition;
+
+        struct VariableDeclaration;
+        struct ArgumentDeclaration;
+
+        struct Statement;
+        
+        struct DoEndBlock;
+        struct IfElseBlock;
+        struct WhileBlock;
+
+        struct Expression;
+
+        struct FeatureCall;
+        struct AssignmentStatement;
+        struct ReturnStatement;
+        struct LocalVariableStatement;
+        struct AddressExpression;
+        struct IntConst;
+
+        struct Operation;
+        struct UnaryOperation;
+        struct BinaryOperation;
+        
+        struct NewArrayExpression;
+        
+        struct CastExpression;
+    }
+
+    namespace sem
+    {
+        struct SemanticObject;
+        struct Class;
+        
+        class Scope;
+
+//        template<typename T>
+//        using SymbolTable = std::map<std::string, std::unique_ptr<T>>;
+    }
+}
+
+
+
+struct qlow::ast::AstObject :
+    public Visitable<std::unique_ptr<sem::SemanticObject>, sem::Scope&, StructureVisitor>
+{
+    CodePosition pos;
+    
+    inline AstObject(const CodePosition& cp) :
+        pos{ cp } {}
+        
+    virtual ~AstObject(void);
+};
+
+
+struct qlow::ast::Class : public AstObject
+{
+    std::string name;
+    OwningList<FeatureDeclaration> features;
+    
+    inline Class(const std::string& name, OwningList<FeatureDeclaration>& features, const CodePosition& cp) :
+        AstObject{ cp },
+        name{ name }, features(std::move(features))
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&) override;
+};
+
+
+struct qlow::ast::Type : public AstObject
+{
+    inline Type(const CodePosition& cp) :
+        AstObject{ cp }
+    {
+    }
+    
+    virtual std::string asString(void) const = 0;
+    virtual inline std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&) override {}
+};
+
+
+struct qlow::ast::ClassType : public ast::Type
+{
+    std::string typeName;
+    
+    inline ClassType(const std::string& typeName, const CodePosition& cp) :
+        Type{ cp },
+        typeName{ typeName }
+    {
+    }
+    
+    inline ClassType(std::string&& typeName, const CodePosition& cp) :
+        Type{ cp },
+        typeName{ std::move(typeName) }
+    {
+    }
+    
+    inline std::string asString(void) const override { return typeName; }
+};
+
+
+struct qlow::ast::ArrayType : public ast::Type 
+{
+    std::unique_ptr<ast::Type> arrayType;
+    
+    inline ArrayType(std::unique_ptr<ast::Type> arrayType, const CodePosition& cp) :
+        Type{ cp },
+        arrayType{ std::move(arrayType) }
+    {
+    }
+    
+    inline std::string asString(void) const override {
+        return std::string("[") + arrayType->asString() + "]";
+    }
+};
+
+
+struct qlow::ast::PointerType : public ast::Type 
+{
+    std::unique_ptr<ast::Type> derefType;
+    
+    inline PointerType(std::unique_ptr<ast::Type> derefType, const CodePosition& cp) :
+        Type{ cp },
+        derefType{ std::move(derefType) }
+    {
+    }
+    
+    inline std::string asString(void) const override {
+        return derefType->asString() + "*";
+    }
+};
+
+
+struct qlow::ast::FeatureDeclaration : public AstObject
+{
+    std::string name;
+    std::unique_ptr<ast::Type> type;
+
+    inline FeatureDeclaration(std::unique_ptr<ast::Type> type, const std::string& name, const CodePosition& cp) :
+        AstObject{ cp },
+        name{ name },
+        type{ std::move(type) }
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::FieldDeclaration : public FeatureDeclaration
+{
+    inline FieldDeclaration(std::unique_ptr<ast::Type> type, const std::string& name, const CodePosition& cp) :
+        FeatureDeclaration{ std::move(type), name, cp }
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::MethodDefinition : public FeatureDeclaration
+{
+    OwningList<ArgumentDeclaration> arguments;
+    
+    /// pointer to method body. If this is a null pointer, the method has only
+    /// been declared and not defined (with extern)
+    std::unique_ptr<DoEndBlock> body;
+
+    inline MethodDefinition(std::unique_ptr<ast::Type> type, const std::string& name,
+            std::unique_ptr<DoEndBlock> body, const CodePosition& cp) :
+        FeatureDeclaration{ std::move(type), name, cp },
+        body{ std::move(body) }
+    {
+    }
+
+
+    inline MethodDefinition(std::unique_ptr<ast::Type> type, const std::string& name,
+            OwningList<ArgumentDeclaration>&& arguments, std::unique_ptr<DoEndBlock> body, const CodePosition& cp) :
+        FeatureDeclaration{ std::move(type), name, cp },
+        arguments(std::move(arguments)),
+        body{ std::move(body) }
+    {
+    }
+
+    
+    inline MethodDefinition(std::unique_ptr<ast::Type> type, const std::string& name,
+            const CodePosition& cp) :
+        FeatureDeclaration{ std::move(type), name, cp },
+        body{ nullptr }
+    {
+    }
+    
+
+    inline MethodDefinition(std::unique_ptr<ast::Type> type, const std::string& name,
+            OwningList<ArgumentDeclaration>&& arguments, const CodePosition& cp) :
+        FeatureDeclaration{ std::move(type), name, cp },
+        arguments(std::move(arguments)),
+        body{ nullptr }
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::VariableDeclaration : public AstObject
+{
+    std::unique_ptr<ast::Type> type;
+    std::string name;
+    inline VariableDeclaration(std::unique_ptr<ast::Type> type, std::string&& name, const CodePosition& cp) :
+        AstObject{ cp },
+        type{ std::move(type) },
+        name{ std::move(name) }
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::ArgumentDeclaration :
+    public VariableDeclaration
+{
+    inline ArgumentDeclaration(std::unique_ptr<ast::Type> type, std::string&& name, const CodePosition& cp) :
+        VariableDeclaration{ std::move(type), std::move(name), cp }
+    {
+    }
+
+    //virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::Statement : public virtual AstObject
+{
+    inline Statement(const CodePosition& cp) :
+        AstObject{ cp } {}
+        
+    virtual ~Statement(void);
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::DoEndBlock : public Statement 
+{
+    OwningList<Statement> statements;
+    
+    inline DoEndBlock(OwningList<Statement>&& statements, const CodePosition& cp) :
+        AstObject{ cp },
+        Statement{ cp },
+        statements(std::move(statements))
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::IfElseBlock : public Statement
+{
+    std::unique_ptr<Expression> condition;
+    std::unique_ptr<DoEndBlock> ifBlock;
+    std::unique_ptr<DoEndBlock> elseBlock;
+    
+    inline IfElseBlock(std::unique_ptr<Expression> condition,
+                       std::unique_ptr<DoEndBlock> ifBlock,
+                       std::unique_ptr<DoEndBlock> elseBlock,
+                       const CodePosition& cp) :
+        AstObject{ cp },
+        Statement{ cp },
+        condition{ std::move(condition) },
+        ifBlock{ std::move(ifBlock) },
+        elseBlock{ std::move(elseBlock) }
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::WhileBlock : public Statement
+{
+    std::unique_ptr<Expression> condition;
+    std::unique_ptr<DoEndBlock> body;
+    
+    inline WhileBlock(std::unique_ptr<Expression> condition,
+                      std::unique_ptr<DoEndBlock> body,
+                      const CodePosition& cp) :
+        AstObject{ cp },
+        Statement{ cp },
+        condition{ std::move(condition) },
+        body{ std::move(body) }
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::Expression : public virtual AstObject
+{
+    inline Expression(const CodePosition& cp) :
+        AstObject{ cp } {}
+        
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::FeatureCall : public Expression, public Statement
+{
+    std::unique_ptr<Expression> target;
+    std::string name;
+    OwningList<Expression> arguments;
+
+    inline FeatureCall(std::unique_ptr<Expression> target, const std::string& name, const CodePosition& cp) :
+        AstObject{ cp },
+        Expression{ cp }, Statement{ cp },
+        target(std::move(target)), name(name)
+    {
+    }
+
+
+    inline FeatureCall(std::unique_ptr<Expression> target, const std::string& name,
+            OwningList<Expression>&& arguments, const CodePosition& cp) :
+        AstObject{ cp },
+        Expression{ cp }, Statement{ cp },
+        target(std::move(target)), name(name), arguments(std::move(arguments))
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::ReturnStatement : public Statement
+{
+    std::unique_ptr<Expression> expr;
+
+    inline ReturnStatement(std::unique_ptr<Expression>&& expr, const CodePosition& cp) :
+        AstObject{ cp },
+        Statement{ cp },
+        expr{ std::move(expr) }
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::AssignmentStatement : public Statement
+{
+    std::unique_ptr<Expression> target;
+    std::unique_ptr<Expression> expr;
+
+    inline AssignmentStatement(std::unique_ptr<Expression>&& target, std::unique_ptr<Expression>&& expr, const CodePosition& cp) :
+        AstObject{ cp },
+        Statement{ cp },
+        target{ std::move(target) }, expr{ std::move(expr) }
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::LocalVariableStatement : public Statement
+{
+    std::string name;
+    std::unique_ptr<ast::Type> type;
+    inline LocalVariableStatement(std::string&& name, std::unique_ptr<Type> type, const CodePosition& cp) :
+        AstObject{ cp },
+        Statement{ cp },
+       name{ name },
+       type{ std::move(type) }
+    {
+    } 
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::AddressExpression : public Expression
+{
+    std::unique_ptr<Expression> target;
+    inline AddressExpression(std::unique_ptr<Expression> target,
+                             const CodePosition& cp) :
+        AstObject{ cp },
+        Expression{ cp },
+       target{ std::move(target) }
+    {
+    } 
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::IntConst : public Expression
+{
+    unsigned long long value;
+    
+    IntConst(unsigned long long v, const CodePosition& p) :
+        AstObject(p),
+        Expression(p),
+        value{ v } {}
+        
+    IntConst(std::string&& val, const CodePosition& p);
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::Operation : public Expression
+{
+    std::string opString;
+    CodePosition opPos;
+
+    inline Operation(const std::string& opString, const CodePosition& cp,
+                     const CodePosition& opPos) :
+        AstObject{ cp },
+        Expression{ cp },
+        opString{ opString },
+        opPos{ opPos }
+    {
+    }
+};
+
+
+struct qlow::ast::UnaryOperation : public Operation
+{
+    enum Side
+    {
+        PREFIX,
+        SUFFIX,
+    };
+
+    Side side;
+    std::unique_ptr<Expression> expr;
+
+    inline UnaryOperation(std::unique_ptr<Expression> expr, Side side,
+                          const std::string& op, const CodePosition& cp,
+                          const CodePosition& opPos
+                         ) :
+        AstObject{ cp },
+        Operation{ op, cp, opPos },
+        side{ side },
+        expr{ std::move(expr) }
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::BinaryOperation : public Operation
+{
+    std::unique_ptr<Expression> left;
+    std::unique_ptr<Expression> right;
+
+    inline BinaryOperation(std::unique_ptr<Expression> left,
+                           std::unique_ptr<Expression> right,
+                           const std::string& op,
+                           const CodePosition& cp,
+                           const CodePosition& opPos
+                          ) :
+        AstObject{ cp },
+        Operation{ op, cp, opPos },
+        left{ std::move(left) },
+        right{ std::move(right) }
+    {
+    }
+
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::NewArrayExpression : public Expression
+{
+    std::unique_ptr<ast::Type> type;
+    std::unique_ptr<Expression> length;
+    inline NewArrayExpression(std::unique_ptr<ast::Type> type,
+                              std::unique_ptr<Expression> length,
+                              const CodePosition& cp) :
+        AstObject{ cp },
+        Expression{ cp },
+        type{ std::move(type) },
+        length{ std::move(length) }
+    {
+    }
+    
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+struct qlow::ast::CastExpression : public Expression
+{
+    std::unique_ptr<ast::Expression> expression;
+    std::unique_ptr<ast::Type> targetType;
+    
+    inline CastExpression(std::unique_ptr<ast::Expression> expression,
+                          std::unique_ptr<ast::Type> targetType,
+                          const CodePosition& cp) :
+        AstObject{ cp },
+        Expression{ cp },
+        expression{ std::move(expression) },
+        targetType{ std::move(targetType) }
+    {
+    }
+    
+    virtual std::unique_ptr<sem::SemanticObject> accept(StructureVisitor& v, sem::Scope&);
+};
+
+
+#endif // QLOW_AST_H
+
+

BIN
src/ast/Ast.o


+ 419 - 0
src/ast/AstVisitor.cpp

@@ -0,0 +1,419 @@
+#include "AstVisitor.h"
+#include "Ast.h"
+#include "ErrorReporting.h"
+
+#include <typeinfo>
+
+#include "Util.h"
+
+using namespace qlow;
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::Class& ast, sem::Scope& scope)
+{
+    //auto c = std::make_unique<sem::Class>();
+    //c->name = ast.name;
+    //return c;
+    throw "shouldn't be called";
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FeatureDeclaration& ast, sem::Scope& scope)
+{
+    // not needed, because 
+    throw "shouldn't be called";
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FieldDeclaration& ast, sem::Scope& scope)
+{
+    auto f = std::make_unique<sem::Field>();
+    f->name = ast.name;
+    auto type = scope.getType(*ast.type);
+    if (type) {
+        f->type = type;
+    }
+    else {
+        throw SemanticError(SemanticError::UNKNOWN_TYPE,
+            ast.type->asString(),
+            ast.type->pos
+        );
+    }
+    return f;
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::MethodDefinition& ast, sem::Scope& scope)
+{
+    auto returnType = scope.getType(*ast.type);
+    if (!returnType) {
+        throw SemanticError(SemanticError::UNKNOWN_TYPE,
+            ast.type->asString(),
+            ast.type->pos
+        );
+    }
+    auto m = std::make_unique<sem::Method>(scope, returnType);
+    m->name = ast.name;
+    m->astNode = &ast;
+    
+    for (auto& arg : ast.arguments) {
+        auto var = arg->accept(*this, scope);
+        if (dynamic_cast<sem::Variable*>(var.get())) {
+            std::unique_ptr<sem::Variable> variable =
+                unique_dynamic_cast<sem::Variable>(std::move(var));
+            variable->isParameter = true;
+            m->arguments.push_back(variable.get());
+            std::string varname = variable->name;
+            m->scope.putVariable(varname, std::move(variable));
+        }
+        else {
+            throw "internal error creating argument";
+        }
+    }
+    
+    return m;
+    //throw "  std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::MethodDefinition& ast, sem::Scope& scope) shouldn't be called";
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::VariableDeclaration& ast, sem::Scope& scope)
+{
+    auto v = std::make_unique<sem::Variable>();
+    v->name = ast.name;
+    auto type = scope.getType(*ast.type);
+    if (type) {
+        v->type = std::move(type);
+    }
+    else {
+        throw SemanticError(SemanticError::UNKNOWN_TYPE,
+            ast.type->asString(),
+            ast.type->pos
+        );
+    }
+    return v;
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::Statement& ast, sem::Scope& scope)
+{
+    printf("at: %d:%d to %d:%d\n", ast.pos.first_line, ast.pos.first_column, ast.pos.last_line, ast.pos.last_column);
+    printf("type: %s\n", typeid(ast).name());
+    throw "visit(Statement) shouldn't be called";
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::DoEndBlock& ast, sem::Scope& scope)
+{
+    sem::LocalScope* lscope = dynamic_cast<sem::LocalScope*>(&scope);
+    if (!lscope)
+        throw "error: non-method scope inside method";
+    auto body = std::make_unique<sem::DoEndBlock>(*lscope);
+    for (auto& statement : ast.statements) {
+        
+        if (ast::LocalVariableStatement* nvs = dynamic_cast<ast::LocalVariableStatement*>(statement.get()); nvs) {
+            auto type = body->scope.getType(*nvs->type);
+
+            if (!type)
+                throw SemanticError(SemanticError::UNKNOWN_TYPE,
+                                    nvs->type->asString(),
+                                    nvs->type->pos);
+            auto var = std::make_unique<sem::Variable>(std::move(type), nvs->name);
+            body->scope.putVariable(nvs->name, std::move(var));
+            continue;
+        }
+        
+        auto v = statement->accept(*this, body->scope);
+        if (dynamic_cast<sem::MethodCallExpression*>(v.get()) != nullptr) {
+            body->statements.push_back(
+                std::make_unique<sem::FeatureCallStatement>(
+                unique_dynamic_cast<sem::MethodCallExpression>(std::move(v))));
+        }
+        else {
+            body->statements.push_back(unique_dynamic_cast<sem::Statement>(std::move(v)));
+        }
+    }
+    return body;
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::IfElseBlock& ast, sem::Scope& scope)
+{
+    auto condition = ast.condition->accept(*this, scope);
+    auto ifB = ast.ifBlock->accept(*this, scope);
+    auto eB= ast.elseBlock->accept(*this, scope);
+    
+    if (!dynamic_cast<sem::DoEndBlock*>(ifB.get())
+        || !dynamic_cast<sem::DoEndBlock*>(eB.get())
+        || !dynamic_cast<sem::Expression*>(condition.get()))
+        throw "internal error, invalid if block";
+    
+    auto condExpr = unique_dynamic_cast<sem::Expression>(std::move(condition));
+    auto ifBBlock = unique_dynamic_cast<sem::DoEndBlock>(std::move(ifB));
+    auto eBBlock= unique_dynamic_cast<sem::DoEndBlock>(std::move(eB));
+    
+    auto ieb = std::make_unique<sem::IfElseBlock>(std::move(condExpr), std::move(ifBBlock), std::move(eBBlock));
+    
+    return ieb;
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::WhileBlock& ast, sem::Scope& scope)
+{
+    auto condition = ast.condition->accept(*this, scope);
+    auto body = ast.body->accept(*this, scope);
+    
+    if (!dynamic_cast<sem::DoEndBlock*>(body.get()) ||
+        !dynamic_cast<sem::Expression*>(condition.get()))
+        throw "internal error, invalid while block";
+    
+    auto condExpr = unique_dynamic_cast<sem::Expression>(std::move(condition));
+    auto bodyblock = unique_dynamic_cast<sem::DoEndBlock>(std::move(body));
+    
+    auto wb = std::make_unique<sem::WhileBlock>(std::move(condExpr), std::move(bodyblock));
+    
+    return wb;
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::Expression& ast, sem::Scope& scope)
+{
+    throw "visit(Expression) shouldn't be called";
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::FeatureCall& ast, sem::Scope& scope)
+{
+    std::unique_ptr<sem::Expression> target = nullptr;
+    if (ast.target) {
+        target = unique_dynamic_cast<sem::Expression>(
+            ast.target->accept(*this, scope));
+    }
+    
+    sem::Method* method;
+    sem::Variable* var;
+    
+    if (target) {
+        method = target->type->getScope().getMethod(ast.name);
+        var = target->type->getScope().getVariable(ast.name);
+    }
+    else {
+        method = scope.getMethod(ast.name);
+        var = scope.getVariable(ast.name);
+    }
+    
+    if (target) {
+        if (var) {
+            return std::make_unique<sem::FieldAccessExpression>(std::move(target), dynamic_cast<sem::Field*>(var));
+        }
+        else if (method) {
+            auto fce = std::make_unique<sem::MethodCallExpression>(
+                std::move(target), method);
+    
+            if (ast.arguments.size() != method->arguments.size())
+                throw SemanticError(SemanticError::WRONG_NUMBER_OF_ARGUMENTS, ast.name, ast.pos);
+            for (size_t i = 0; i < ast.arguments.size(); i++) {
+                auto& arg = ast.arguments[i];
+                auto& argTypeShouldHave = method->arguments[i]->type;
+                auto argument = arg->accept(*this, scope);
+                if (sem::Expression* expr =
+                        dynamic_cast<sem::Expression*>(argument.get()); expr) {
+                    if (!expr->type->equals(*argTypeShouldHave))
+                        throw SemanticError(SemanticError::TYPE_MISMATCH,
+                            "argument passed to function has wrong type: '" +
+                            expr->type->asString() + "' instead of '" +
+                            argTypeShouldHave->asString() + "'",
+                            arg->pos
+                        );
+                    fce->arguments.push_back(
+                        unique_dynamic_cast<sem::Expression>(std::move(argument)));
+                }
+                else {
+                    throw "internal error: non-expression passed as function parameter";
+                }
+            }
+            return fce;
+        }
+        else {
+            throw SemanticError(SemanticError::FEATURE_NOT_FOUND, ast.name, ast.pos);
+        }
+    }
+    else if (var) {
+        if (sem::Field* field = dynamic_cast<sem::Field*>(var); field) {
+            auto* thisExpr = scope.getVariable("this");
+            if (!thisExpr)
+                throw "no this found";
+            Logger::getInstance().debug() << "feature call " << var->toString() << " is a field\n";
+            return std::make_unique<sem::FieldAccessExpression>(std::make_unique<sem::LocalVariableExpression>(thisExpr), field);
+        }
+        else {
+            Logger::getInstance().debug() << "feature call " << var->toString() << " is not a field\n";
+            return std::make_unique<sem::LocalVariableExpression>(var);
+        }
+    }
+    else if (method) {
+        auto fce = std::make_unique<sem::MethodCallExpression>(nullptr, method);
+        for (auto& arg : ast.arguments) {
+            auto argument = arg->accept(*this, scope);
+            if (dynamic_cast<sem::Expression*>(argument.get())) {
+                fce->arguments.push_back(unique_dynamic_cast<sem::Expression>(std::move(argument)));
+            }
+            else {
+                throw "internal error: non-expression passed as function parameter";
+            }
+        }
+        fce->callee = method;
+        return fce;
+    }
+    else {
+#ifdef DEBUGGING
+        printf("var not found: %s\n", ast.name.c_str());
+        printf("current scope: %s\n", scope.toString().c_str());
+#endif
+        throw SemanticError(SemanticError::FEATURE_NOT_FOUND, ast.name, ast.pos);
+    }
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::AssignmentStatement& ast, sem::Scope& scope)
+{
+    auto as = std::make_unique<sem::AssignmentStatement>();
+    
+//    as->value = unique_dynamic_cast<sem::Expression>(visit(*ast.expr, classes));
+//    as->target = unique_dynamic_cast<sem::Expression>(visit(*ast.target, classes));
+    as->value = unique_dynamic_cast<sem::Expression>(ast.expr->accept(*this, scope));
+    as->target = unique_dynamic_cast<sem::Expression>(ast.target->accept(*this, scope));
+    
+    if (as->target->type->equals(*as->value->type)) {
+        return as;
+    }
+    else {
+        throw SemanticError(
+            SemanticError::TYPE_MISMATCH,
+            "Can't assign expression of type '" + as->value->type->asString() +
+            "' to value of type '" + as->target->type->asString() + "'.",
+            ast.pos
+        );
+    }
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::ReturnStatement& ast, sem::Scope& scope)
+{
+    auto shouldReturn = scope.getReturnableType();
+    
+    if (shouldReturn == nullptr) {
+        if (ast.expr == nullptr)
+            return std::make_unique<sem::ReturnStatement>();
+        else
+            throw SemanticError(
+                SemanticError::INVALID_RETURN_TYPE,
+                "This method should not return any value.",
+                ast.expr->pos
+            );
+    }
+    else if (ast.expr == nullptr) {
+        throw SemanticError(
+            SemanticError::INVALID_RETURN_TYPE,
+            "This method should return a value.",
+            ast.pos
+        );
+    }
+    
+    auto returnValue = unique_dynamic_cast<sem::Expression>(ast.expr->accept(*this, scope));
+    
+    if (!shouldReturn->equals(*returnValue->type)) {
+        throw SemanticError(
+            SemanticError::INVALID_RETURN_TYPE,
+            "return value must be of type '" + shouldReturn->asString() + "' (not '" +
+            returnValue->type->asString() + "')",
+            ast.expr->pos
+        );
+    }
+    
+    auto as = std::make_unique<sem::ReturnStatement>();
+    as->value = std::move(returnValue);
+    return as;
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::LocalVariableStatement& ast, sem::Scope& scope)
+{
+    throw "shouldn't be called";
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(
+    ast::AddressExpression& ast, sem::Scope& scope)
+{
+    auto target = unique_dynamic_cast<sem::Expression>(ast.target->accept(*this, scope));
+    auto& targetType = target->type;
+    
+    if (!target->isLValue()) {
+        throw NotLValue(targetType->asString(), ast.pos);
+    }
+    
+    return std::make_unique<sem::AddressExpression>(std::move(target));
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::IntConst& ast, sem::Scope& scope)
+{
+    return std::make_unique<sem::IntConst>(ast.value);
+}
+
+
+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>(argument->type);
+            // TODO not a feasible assumption
+    ret->opString = ast.opString;
+    ret->side = ast.side;
+    ret->arg = std::move(argument);
+    return ret;
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::BinaryOperation& ast, sem::Scope& scope)
+{
+    auto leftEval = unique_dynamic_cast<sem::Expression>(ast.left->accept(*this, scope));
+    auto rightEval = unique_dynamic_cast<sem::Expression>(ast.right->accept(*this, scope));
+    
+    sem::Method* operationMethod = leftEval->type->getScope().resolveMethod(
+        ast.opString, { rightEval->type }
+    );
+    
+    Logger::getInstance().debug() << "looked for operation method for operator " <<
+    ast.opString << std::endl;
+    if (!operationMethod) {
+        throw SemanticError(SemanticError::OPERATOR_NOT_FOUND,
+            "operator " + ast.opString + " not found for types '" +
+            leftEval->type->asString() + "' and '" + rightEval->type->asString() + "'",
+            ast.opPos);
+    }
+    
+    auto ret = std::make_unique<sem::BinaryOperation>(leftEval->type, &ast);
+    
+    ret->operationMethod = operationMethod;
+    ret->opString = ast.opString;
+    ret->left = std::move(leftEval);
+    ret->right = std::move(rightEval);
+    return ret;
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::NewArrayExpression& ast, sem::Scope& scope)
+{
+    auto ret = std::make_unique<sem::NewArrayExpression>(scope.getType(*ast.type));
+    return ret;
+}
+
+
+std::unique_ptr<sem::SemanticObject> StructureVisitor::visit(ast::CastExpression& ast, sem::Scope& scope)
+{
+    auto expr = unique_dynamic_cast<sem::Expression>(ast.expression->accept(*this, scope));
+    auto type = scope.getType(*ast.targetType);
+    return std::make_unique<sem::CastExpression>(
+        std::move(expr), std::move(type), &ast);
+}
+

+ 87 - 0
src/ast/AstVisitor.h

@@ -0,0 +1,87 @@
+#ifndef QLOW_AST_VISITOR_H
+#define QLOW_AST_VISITOR_H
+
+#include "Visitor.h"
+#include "Ast.h"
+#include "Semantic.h"
+#include "Builtin.h"
+#include "Scope.h"
+
+
+#include <memory>
+
+
+namespace qlow
+{
+    namespace ast
+    {
+        template<typename T>
+        using List = std::vector<std::unique_ptr<T>>;
+    }
+}
+
+
+namespace qlow
+{
+    class StructureVisitor;
+}
+
+
+class qlow::StructureVisitor :
+    public Visitor<
+        std::unique_ptr<sem::SemanticObject>,
+        sem::Scope&,
+
+        ast::Class,
+        ast::FeatureDeclaration,
+        ast::FieldDeclaration,
+        ast::MethodDefinition,
+        ast::VariableDeclaration,
+        ast::Statement,
+        ast::DoEndBlock,
+        ast::IfElseBlock,
+        ast::WhileBlock,
+        ast::Expression,
+        ast::FeatureCall,
+        ast::AssignmentStatement,
+        ast::ReturnStatement,
+        ast::LocalVariableStatement,
+        ast::AddressExpression,
+        ast::IntConst,
+        ast::UnaryOperation,
+        ast::BinaryOperation,
+        ast::NewArrayExpression,
+        ast::CastExpression
+    >
+{
+public:
+    using ReturnType = std::unique_ptr<sem::SemanticObject>;
+
+    ReturnType visit(ast::Class& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::FeatureDeclaration& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::FieldDeclaration& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::MethodDefinition& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::VariableDeclaration& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::Statement& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::DoEndBlock& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::IfElseBlock& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::WhileBlock& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::Expression& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::FeatureCall& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::AssignmentStatement& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::ReturnStatement& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::LocalVariableStatement& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::AddressExpression& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::IntConst& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::UnaryOperation& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::BinaryOperation& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::NewArrayExpression& ast, sem::Scope& scope) override;
+    ReturnType visit(ast::CastExpression& ast, sem::Scope& scope) override;
+};
+
+
+
+
+#endif // QLOW_AST_VISITOR_H
+
+

BIN
src/ast/AstVisitor.o