From 05b0f72ae5a41df738ab474e7f2c2e1f31d7b7e2 Mon Sep 17 00:00:00 2001 From: kemo Date: Wed, 25 Jan 2023 00:25:08 +0200 Subject: [PATCH] this is a huge mess but i have to compile llvm myself :( --- Custom-lang/Compile/Compiler.ixx | 181 +++++++++++++++++++--- Custom-lang/Compile/KaleidoscopeJIT.h | 116 ++++++++++++++ Custom-lang/Compile/LLVM.h | 15 +- Custom-lang/Custom-lang.cpp | 27 ++++ Custom-lang/Custom-lang.vcxproj | 7 +- Custom-lang/Custom-lang.vcxproj.filters | 20 ++- Custom-lang/Frontend/AST/Core.ixx | 13 +- Custom-lang/Frontend/AST/Expressions.ixx | 4 +- Custom-lang/Frontend/AST/Statements.ixx | 44 +++++- Custom-lang/Frontend/Lexer.ixx | 4 +- Custom-lang/Frontend/Parser.ixx | 74 +++++++-- Custom-lang/Runtime/Interpreter/Exprs.ixx | 22 +-- Custom-lang/test.hz | 12 +- 13 files changed, 472 insertions(+), 67 deletions(-) create mode 100644 Custom-lang/Compile/KaleidoscopeJIT.h diff --git a/Custom-lang/Compile/Compiler.ixx b/Custom-lang/Compile/Compiler.ixx index 8546e84..8ab72e6 100644 --- a/Custom-lang/Compile/Compiler.ixx +++ b/Custom-lang/Compile/Compiler.ixx @@ -9,24 +9,59 @@ import AST.Statements; import AST.Expressions; import Reflection; import ; +import ; -static Shared TheContext = std::make_unique(); -static Shared TheModule = std::make_unique("my cool jit", *TheContext); -static Shared> Builder = std::make_unique>(*TheContext); -static UnorderedMap NamedValues; +import "KaleidoscopeJIT.h"; + +export Unique TheContext; +export Unique TheModule; +export Unique> Builder; +export Unique TheFPM; + +export Unique TheJIT; + +UnorderedMap NamedValues; + +UnorderedMap> Externs; + +llvm::Type* TypeNameToLLVMType(String typeName) +{ + if (typeName == "Int") + { + return llvm::Type::getInt64Ty(*TheContext); + } + else if (typeName == "Float") + { + return llvm::Type::getDoubleTy(*TheContext); + } + else if (typeName == "Bool") + { + return llvm::Type::getInt1Ty(*TheContext); + } + else if (typeName == "String") + { + return llvm::Type::getInt8PtrTy(*TheContext); + } + else + { + Safety::Throw(std::format("Unknown type: '{}'", typeName)); + } + + return llvm::Type::getInt8PtrTy(*TheContext); +} llvm::Value* Compile(Shared node); llvm::Value* CompileProgram(Shared node) { - llvm::Value* lastValue = nullptr; + llvm::Value* LastValue = nullptr; for (auto&& Stmt : node->Body) { - lastValue = Compile(Stmt); + LastValue = Compile(Stmt); } - return lastValue; + return LastValue; } llvm::Value* CompileIntLiteral(Shared node) @@ -46,14 +81,14 @@ llvm::Value* CompileStringLiteral(Shared node) llvm::Value* CompileIdentifier(Shared node) { - auto value = NamedValues[node->Name]; + auto Value = NamedValues[node->Name]; - if (!value) + if (!Value) { Safety::Throw(std::format("Unknown variable name '{0}'", node->Name)); } - return value; + return Value; } llvm::Value* CompileBinaryExpr(Shared node) @@ -66,33 +101,137 @@ llvm::Value* CompileBinaryExpr(Shared node) Safety::Throw("Invalid binary expression"); } - if (node->Operator == "+") + switch (node->Operator) { - return Builder->CreateFAdd(Left, Right, "addtmp"); + case '+': + return Builder->CreateAdd(Left, Right, "addtmp"); + case '-': + return Builder->CreateSub(Left, Right, "subtmp"); + case '*': + return Builder->CreateMul(Left, Right, "multmp"); + case '/': + return Builder->CreateUDiv(Left, Right, "divtmp"); + default: + Safety::Throw(std::format("Invalid binary operator: '{0}'", node->Operator)); } - else if (node->Operator == "-") + + return nullptr; +} + +llvm::Value* CompileFunctionDeclaration(Shared node) +{ + Vector ArgsTypes; + + for (auto&& Arg : node->Parameters) { - return Builder->CreateFSub(Left, Right, "subtmp"); + ArgsTypes.push_back(TypeNameToLLVMType(Arg.first)); } - else if (node->Operator == "*") + + auto FunctionType = llvm::FunctionType::get(TypeNameToLLVMType(node->ReturnType), ArgsTypes, false); + + auto Function = llvm::Function::Create(FunctionType, llvm::Function::ExternalLinkage, node->Name, *TheModule); + + auto BB = llvm::BasicBlock::Create(*TheContext, "entry", Function); + + Builder->SetInsertPoint(BB); + + for (auto i = 0; i < node->Parameters.size(); i++) { - return Builder->CreateFMul(Left, Right, "multmp"); + auto Param = node->Parameters[i]; + + auto Arg = Function->arg_begin() + i; + + Arg->setName(Param.second); + + NamedValues[Param.second] = Arg; } - else if (node->Operator == "/") + + llvm::Value* ReturnValue = nullptr; + + for (auto&& Stmt : node->Body) + { + ReturnValue = Compile(Stmt); + } + + if (node->ReturnType == "Void" || !ReturnValue) { - return Builder->CreateFDiv(Left, Right, "divtmp"); + Builder->CreateRetVoid(); } + else + { + Builder->CreateRet(ReturnValue); + } + + llvm::verifyFunction(*Function); + + TheFPM->run(*Function); + + return Function; +} + +llvm::Value* CompileCallExpr(Shared node) +{ + auto Name = node->Callee->As()->Name; + + if (auto CalleeF = TheModule->getFunction(Name)) + { + if (CalleeF->arg_size() != node->Arguments.size()) + { + Safety::Throw(std::format("Incorrect number of arguments passed to '{0}'", Name)); + } + + Vector ArgsV; + + for (auto&& Arg : node->Arguments) + { + ArgsV.push_back(Compile(Arg)); + } + + return Builder->CreateCall(CalleeF, ArgsV, "calltmp"); + } +} + +llvm::Value* CompileExternDeclaration(Shared node) +{ + Externs[node->Identifier] = node; return nullptr; } export llvm::Value* Compile(Shared node) { + // auto expr = std::dynamic_pointer_cast(node); + + // if (expr) + { + // if (expr->bIsTopLevel) + { + auto RT = TheJIT->getMainJITDylib().createResourceTracker(); + + auto TSM = llvm::orc::ThreadSafeModule(std::move(TheModule), std::move(TheContext)); + TheJIT->addModule(std::move(TSM), RT); + + // Search the JIT for the __anon_expr symbol. + auto ExprSymbol = TheJIT->lookup("__anon_expr"); + + // Get the symbol's address and cast it to the right type (takes no + // arguments, returns a double) so we can call it as a native function. + double (*FP)() = (double (*)())(intptr_t)ExprSymbol->getAddress(); + fprintf(stderr, "Evaluated to %f\n", FP()); + + // Delete the anonymous expression module from the JIT. + RT->remove(); + } + } + switch (node->Type) { case ASTNodeType::Program: return CompileProgram(node->As()); + case ASTNodeType::Identifier: + return CompileIdentifier(node->As()); + case ASTNodeType::IntLiteral: return CompileIntLiteral(node->As()); @@ -105,6 +244,12 @@ export llvm::Value* Compile(Shared node) case ASTNodeType::BinaryExpr: return CompileBinaryExpr(node->As()); + case ASTNodeType::FunctionDeclaration: + return CompileFunctionDeclaration(node->As()); + + case ASTNodeType::CallExpr: + return CompileCallExpr(node->As()); + default: return Safety::Throw(std::format("Unknown AST node type: {}", Reflection::EnumToString(node->Type))); } diff --git a/Custom-lang/Compile/KaleidoscopeJIT.h b/Custom-lang/Compile/KaleidoscopeJIT.h new file mode 100644 index 0000000..c2cdb44 --- /dev/null +++ b/Custom-lang/Compile/KaleidoscopeJIT.h @@ -0,0 +1,116 @@ +//===- KaleidoscopeJIT.h - A simple JIT for Kaleidoscope --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Contains a simple JIT definition for use in the kaleidoscope tutorials. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H +#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" +#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" +#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/LLVMContext.h" +#include + +namespace llvm +{ + namespace orc + { + + class KaleidoscopeJIT + { + private: + std::unique_ptr ES; + + DataLayout DL; + MangleAndInterner Mangle; + + RTDyldObjectLinkingLayer ObjectLayer; + IRCompileLayer CompileLayer; + + JITDylib& MainJD; + + public: + KaleidoscopeJIT(std::unique_ptr ES, + JITTargetMachineBuilder JTMB, DataLayout DL) + : ES(std::move(ES)) + , DL(std::move(DL)) + , Mangle(*this->ES, this->DL) + , ObjectLayer(*this->ES, + []() + { return std::make_unique(); }) + , CompileLayer(*this->ES, ObjectLayer, + std::make_unique(std::move(JTMB))) + , MainJD(this->ES->createBareJITDylib("
")) + { + MainJD.addGenerator( + cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( + DL.getGlobalPrefix()))); + if (JTMB.getTargetTriple().isOSBinFormatCOFF()) + { + ObjectLayer.setOverrideObjectFlagsWithResponsibilityFlags(true); + ObjectLayer.setAutoClaimResponsibilityForObjectSymbols(true); + } + } + + ~KaleidoscopeJIT() + { + if (auto Err = ES->endSession()) + ES->reportError(std::move(Err)); + } + + static Expected> Create() + { + auto EPC = SelfExecutorProcessControl::Create(); + if (!EPC) + return EPC.takeError(); + + auto ES = std::make_unique(std::move(*EPC)); + + JITTargetMachineBuilder JTMB( + ES->getExecutorProcessControl().getTargetTriple()); + + auto DL = JTMB.getDefaultDataLayoutForTarget(); + if (!DL) + return DL.takeError(); + + return std::make_unique(std::move(ES), std::move(JTMB), + std::move(*DL)); + } + + const DataLayout& getDataLayout() const { return DL; } + + JITDylib& getMainJITDylib() { return MainJD; } + + Error addModule(ThreadSafeModule TSM, ResourceTrackerSP RT = nullptr) + { + if (!RT) + RT = MainJD.getDefaultResourceTracker(); + return CompileLayer.add(RT, std::move(TSM)); + } + + Expected lookup(StringRef Name) + { + return ES->lookup({ &MainJD }, Mangle(Name.str())); + } + }; + + } // end namespace orc +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H \ No newline at end of file diff --git a/Custom-lang/Compile/LLVM.h b/Custom-lang/Compile/LLVM.h index 0d28e07..2679659 100644 --- a/Custom-lang/Compile/LLVM.h +++ b/Custom-lang/Compile/LLVM.h @@ -1,13 +1,26 @@ #pragma once #include "llvm/ADT/APFloat.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" -#include "llvm/IR/Verifier.h" \ No newline at end of file +#include "llvm/IR/Verifier.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Transforms/InstCombine/InstCombine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/GVN.h" \ No newline at end of file diff --git a/Custom-lang/Custom-lang.cpp b/Custom-lang/Custom-lang.cpp index a74e0e1..9bf99d2 100644 --- a/Custom-lang/Custom-lang.cpp +++ b/Custom-lang/Custom-lang.cpp @@ -12,6 +12,8 @@ import AST.Core; import Runtime.ExecutionContext; import Interpreter; +import LLVM; + import Compiler; /* @@ -94,7 +96,32 @@ int main(int argc, char** argv) const auto result = Evaluate(program, ctx); // Log("Result: %s", result->ToString().c_str()); + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + llvm::InitializeNativeTargetAsmParser(); + + static llvm::ExitOnError ExitOnErr; + + TheJIT = ExitOnErr(llvm::orc::KaleidoscopeJIT::Create()); + + TheContext = std::make_unique(); + TheModule = std::make_unique("my cool jit", *TheContext); + TheModule->setDataLayout(TheJIT->getDataLayout()); + + Builder = std::make_unique>(*TheContext); + + TheFPM = std::make_unique(TheModule.get()); + + TheFPM->add(llvm::createInstructionCombiningPass()); + TheFPM->add(llvm::createReassociatePass()); + TheFPM->add(llvm::createGVNPass()); + TheFPM->add(llvm::createCFGSimplificationPass()); + + TheFPM->doInitialization(); + Compile(program); + TheModule->print(llvm::errs(), nullptr); + return 0; } diff --git a/Custom-lang/Custom-lang.vcxproj b/Custom-lang/Custom-lang.vcxproj index 52e590f..33fe2b3 100644 --- a/Custom-lang/Custom-lang.vcxproj +++ b/Custom-lang/Custom-lang.vcxproj @@ -141,8 +141,8 @@ Level3 true true - true - NDEBUG;_CONSOLE;_SILENCE_ALL_CXX23_DEPRECATION_WARNINGS;%(PreprocessorDefinitions) + false + NDEBUG;_CONSOLE;_SILENCE_ALL_CXX20_DEPRECATION_WARNINGS;_SILENCE_ALL_CXX23_DEPRECATION_WARNINGS;%(PreprocessorDefinitions) true stdcpplatest true @@ -191,6 +191,9 @@ + + + diff --git a/Custom-lang/Custom-lang.vcxproj.filters b/Custom-lang/Custom-lang.vcxproj.filters index 99ccecf..89be488 100644 --- a/Custom-lang/Custom-lang.vcxproj.filters +++ b/Custom-lang/Custom-lang.vcxproj.filters @@ -102,24 +102,22 @@ Source Files - + Source Files - + + Source Files + + + Header Files + + Source Files - - - - + Header Files - - - Source Files - - \ No newline at end of file diff --git a/Custom-lang/Frontend/AST/Core.ixx b/Custom-lang/Frontend/AST/Core.ixx index d03e4e0..15f48eb 100644 --- a/Custom-lang/Frontend/AST/Core.ixx +++ b/Custom-lang/Frontend/AST/Core.ixx @@ -10,9 +10,13 @@ export { enum class ASTNodeType { + Unknown, + Statement, + Expression, DebugStatement, Program, VariableDeclaration, + ExternDeclaration, FunctionDeclaration, ClassDeclaration, EnumDeclaration, @@ -41,7 +45,7 @@ export struct Statement : public std::enable_shared_from_this { - ASTNodeType Type; + ASTNodeType Type = ASTNodeType::Statement; Statement(ASTNodeType Type) : Type(Type) @@ -76,6 +80,13 @@ export struct Expr : public Statement { + bool bIsTopLevel = true; + + Expr() + : Statement(ASTNodeType::Expression) + { + } + Expr(ASTNodeType Type) : Statement(Type) { diff --git a/Custom-lang/Frontend/AST/Expressions.ixx b/Custom-lang/Frontend/AST/Expressions.ixx index 13c155d..e67cd82 100644 --- a/Custom-lang/Frontend/AST/Expressions.ixx +++ b/Custom-lang/Frontend/AST/Expressions.ixx @@ -89,9 +89,9 @@ export { Shared Left; Shared Right; - String Operator; + char Operator; - BinaryExpr(Shared left, Shared right, String op) + BinaryExpr(Shared left, Shared right, char op) : Expr { ASTNodeType::BinaryExpr } , Left(left) , Right(right) diff --git a/Custom-lang/Frontend/AST/Statements.ixx b/Custom-lang/Frontend/AST/Statements.ixx index 78cb4f8..9fa9093 100644 --- a/Custom-lang/Frontend/AST/Statements.ixx +++ b/Custom-lang/Frontend/AST/Statements.ixx @@ -201,16 +201,51 @@ export } }; + // external functions + struct ExternDeclaration : public Statement + { + String Identifier; + String TypeName; + Vector> Parameters; + + ExternDeclaration(String identifier, String typeName, Vector> parameters) + : Statement { ASTNodeType::ExternDeclaration } + , Identifier(identifier) + , TypeName(typeName) + , Parameters(parameters) + { + } + + virtual String ToString(std::string indentation = "") override + { + std::string output = std::format("{{\n{0}\tType: '{1}',\n{0}\tIdentifier: '{2}',\n{0}\tTypeName: '{3}',\n{0}\tParameters: [", + indentation, Reflection::EnumToString(Type), Identifier, TypeName); + + for (auto&& Parameter : Parameters) + { + output += "\n" + indentation + "\t\t{ Identifier: '" + Parameter.first + "', TypeName: '" + Parameter.second + "' },"; + } + + output += "\n" + indentation + "\t]"; + + output += "\n" + indentation + "}"; + + return output; + } + }; + struct FunctionDeclaration : public Statement { String Name; - Vector> Parameters; + Vector> Parameters; + String ReturnType; Vector> Body; - FunctionDeclaration(String name, Vector> parameters, Vector> body) + FunctionDeclaration(String name, Vector> parameters, String returnType, Vector> body) : Statement { ASTNodeType::FunctionDeclaration } , Name { name } , Parameters { parameters } + , ReturnType(returnType) , Body { body } { } @@ -222,10 +257,11 @@ export for (auto&& Param : Parameters) { - output += "\n" + indentation + "\t\t" + Param->ToString(indentation + "\t\t") + ","; + output += "\n" + indentation + "\t\t{ Identifier: '" + Param.first + "', TypeName: '" + Param.second + "' },"; } - output += "\n" + indentation + "\t],\n" + indentation + "\tBody: ["; + output += "\n" + indentation + "\t],\n{0}\tReturnType: '{3}',\n{0}\tBody: [", + indentation, Reflection::EnumToString(Type), Name, ReturnType; for (auto&& Stmt : Body) { diff --git a/Custom-lang/Frontend/Lexer.ixx b/Custom-lang/Frontend/Lexer.ixx index a899f3e..2f88811 100644 --- a/Custom-lang/Frontend/Lexer.ixx +++ b/Custom-lang/Frontend/Lexer.ixx @@ -23,6 +23,7 @@ export Class, // class Super, // super Enum, // enum + Extern, // extern Function, // function Return, // return Let, // let @@ -90,7 +91,7 @@ export }; private: - static constexpr const FlatMap ReservedKeywords = { + static constexpr const FlatMap ReservedKeywords = { { { { "debug", LexerTokenType::Debug }, { "class", LexerTokenType::Class }, @@ -98,6 +99,7 @@ export { "enum", LexerTokenType::Enum }, { "function", LexerTokenType::Function }, { "return", LexerTokenType::Return }, + { "extern", LexerTokenType::Extern }, { "let", LexerTokenType::Let }, { "const", LexerTokenType::Const }, { "if", LexerTokenType::If }, diff --git a/Custom-lang/Frontend/Parser.ixx b/Custom-lang/Frontend/Parser.ixx index fa06eae..2ff5897 100644 --- a/Custom-lang/Frontend/Parser.ixx +++ b/Custom-lang/Frontend/Parser.ixx @@ -147,7 +147,7 @@ export auto Right = ParseMemberExpr(); - Left = std::make_shared(Left, Right, Operator); + Left = std::make_shared(Left, Right, Operator[0]); } return Left; @@ -163,7 +163,7 @@ export auto Right = ParseMultiplicativeExpr(); - Left = std::make_shared(Left, Right, Operator); + Left = std::make_shared(Left, Right, Operator[0]); } return Left; @@ -336,11 +336,11 @@ export { const auto ParseArgsList = [&]() { - Vector> args; + Vector> Args; while (NotEoF() and Current().Type != LexerTokenType::CloseParen) { - args.emplace_back(ParseExpr()); + Args.emplace_back(ParseExpr()); if (Current().Type != LexerTokenType::CloseParen) { @@ -348,7 +348,7 @@ export } } - return args; + return Args; }; Expect(LexerTokenType::OpenParen, "Expected '('"); @@ -356,7 +356,7 @@ export auto Args = Current().Type == LexerTokenType::CloseParen ? Vector>() : ParseArgsList(); Expect(LexerTokenType::CloseParen, "Expected ')'"); - + return Args; } @@ -437,6 +437,33 @@ export return std::make_shared(Times, Block->Body); } + Vector> ParseParams() + { + Vector> Params; + + Expect(LexerTokenType::OpenParen, "Expected '('"); + + while (Current().Type != LexerTokenType::CloseParen) + { + const auto Name = Expect(LexerTokenType::Identifier, "Unexpected token: " + Current().Value + ", expected a identifier").Value; + + Expect(LexerTokenType::Colon, "Unexpected token: " + Current().Value + ", expected a ':'"); + + const auto Type = Expect(LexerTokenType::Identifier, "Unexpected token: " + Current().Value + ", expected a identifier").Value; + + Params.emplace_back(std::make_pair(Type, Name)); + + if (Current().Type != LexerTokenType::CloseParen) + { + Expect(LexerTokenType::Comma, "Unexpected token: " + Current().Value + ", expected a ','"); + } + } + + Expect(LexerTokenType::CloseParen, "Expected ')'"); + + return Params; + } + Shared ParseFunctionDeclaration() { if (Current().Type == LexerTokenType::Function) @@ -444,13 +471,17 @@ export const auto Name = Expect(LexerTokenType::Identifier, "Unexpected token: " + Current().Value + ", expected a function name").Value; - const auto Parameters = ParseArgs(); + const auto Parameters = ParseParams(); + + Expect(LexerTokenType::Colon, "Unexpected token: " + Current().Value + ", expected a ':'"); + + const auto ReturnType = Expect(LexerTokenType::Identifier, "Unexpected token: " + Current().Value + ", expected a return type").Value; Expect(LexerTokenType::OpenBrace, "Unexpected token: " + Current().Value + ", expected a '{'"); auto Block = ParseBlock(); - return std::make_shared(Name, Parameters, Block->Body); + return std::make_shared(Name, Parameters, ReturnType, Block->Body); } Shared ParseReturnStatement() @@ -464,6 +495,23 @@ export return std::make_shared(Value); } + Shared ParseExternDeclaration() + { + Advance(); // Skip 'extern' + + const auto Name = Expect(LexerTokenType::Identifier, "Unexpected token: " + Current().Value + ", expected a function name").Value; + + const auto Parameters = ParseParams(); + + Expect(LexerTokenType::Colon, "Unexpected token: " + Current().Value + ", expected a ':'"); + + const auto ReturnType = Expect(LexerTokenType::Identifier, "Unexpected token: " + Current().Value + ", expected a return type").Value; + + Expect(LexerTokenType::Semicolon, "Unexpected token: " + Current().Value + ", expected a ';'"); + + return std::make_shared(Name, ReturnType, Parameters); + } + Shared ParseEnumDeclaration() { Advance(); // Skip 'enum' @@ -514,6 +562,9 @@ export case LexerTokenType::Return: return ParseReturnStatement(); + case LexerTokenType::Extern: + return ParseExternDeclaration(); + case LexerTokenType::Let: case LexerTokenType::Const: return ParseVariableDeclaration(); @@ -535,7 +586,9 @@ export return ParseBlock(); default: - return ParseExpr(); + const auto expr = ParseExpr(); + expr->bIsTopLevel = true; + return expr; } } @@ -545,7 +598,8 @@ export auto Value = ParseStatement(); - Expect(LexerTokenType::Semicolon, "Expected ';'"); + if (Current().Type == LexerTokenType::Semicolon) + Advance(); // Skip ';' return std::make_shared(Value); } diff --git a/Custom-lang/Runtime/Interpreter/Exprs.ixx b/Custom-lang/Runtime/Interpreter/Exprs.ixx index 4438752..0fe9425 100644 --- a/Custom-lang/Runtime/Interpreter/Exprs.ixx +++ b/Custom-lang/Runtime/Interpreter/Exprs.ixx @@ -1,5 +1,6 @@ export module Interpreter:Exprs; +import ; import Types.Core; import Safety; import Reflection; @@ -29,24 +30,17 @@ Shared EvalBinaryExpr(Shared node, SharedOperator == "+") + switch (node->Operator) { + case '+': return NullValue::ValueOrNull(left->operator+(right)); - } - else if (node->Operator == "-") - { + case '-': return NullValue::ValueOrNull(left->operator-(right)); - } - else if (node->Operator == "*") - { + case '*': return NullValue::ValueOrNull(left->operator*(right)); - } - else if (node->Operator == "/") - { + case '/': return NullValue::ValueOrNull(left->operator/(right)); - } - else - { + default: Safety::Throw("Tried to evalute an unknown numeric operator!!"); } @@ -198,7 +192,7 @@ Shared RuntimeFunction::Call(Shared context, con auto Param = Declaration->Parameters[i]; auto Arg = arguments[i]; - const auto ParamName = Param->As()->Name; + const auto ParamName = Param.second; NewContext->DeclareVar(ParamName, Evaluate(Arg, context), false); } diff --git a/Custom-lang/test.hz b/Custom-lang/test.hz index 738a120..fe83956 100644 --- a/Custom-lang/test.hz +++ b/Custom-lang/test.hz @@ -1,7 +1,13 @@ -function adder(x, y) { - x + y +//extern putchard(x: Float): Float; + +//putchard(120); + +function adder(x: Int, y: Int): Int +{ + x + y + (2 + 3) } -function subber(x, y) { +function subber(x: Int, y: Int): Int +{ x - y } \ No newline at end of file