Merge pull request #30 from rafalgrodzinski/28-support-for-embedded-assembly
Support for embedded assembly
This commit is contained in:
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -6,7 +6,7 @@
|
|||||||
"type": "lldb-dap",
|
"type": "lldb-dap",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${command:cmake.launchTargetPath}",
|
"program": "${command:cmake.launchTargetPath}",
|
||||||
"args": ["-v", "${workspaceFolder}/samples/hello.brc"],
|
"args": ["-v", "${workspaceFolder}/samples/test.brc"],
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"internalConsoleOptions": "openOnSessionStart",
|
"internalConsoleOptions": "openOnSessionStart",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
@extern putchar fun: character sint32 -> sint32
|
@extern putchar fun: character sint32 -> sint32
|
||||||
|
|
||||||
|
// ./build/brb samples/test.brc -S -x86-asm-syntax=intel
|
||||||
|
|
||||||
/*
|
/*
|
||||||
User type
|
User type
|
||||||
name data<u8, 32>
|
name data<u8, 32>
|
||||||
@@ -18,8 +20,34 @@ i u32 <- 0, rep text[i] != 0:
|
|||||||
|
|
||||||
// text data<u8> <- "Hello world!"
|
// text data<u8> <- "Hello world!"
|
||||||
|
|
||||||
|
/*addStuff asm<"+r, r">: num1 u32, num2 u32 -> u32
|
||||||
|
add $1, $0
|
||||||
|
;*/
|
||||||
|
|
||||||
|
normAdd fun: num1 sint32, num2 sint32 -> sint32
|
||||||
|
ret num1 + num2
|
||||||
|
;
|
||||||
|
|
||||||
|
rawAdd raw<"=r,r,r">: num1 sint32, num2 sint32 -> sint32
|
||||||
|
add $1, $2
|
||||||
|
mov $0, $1
|
||||||
|
;
|
||||||
|
|
||||||
|
/*printChar raw
|
||||||
|
.global REGISTER
|
||||||
|
.text
|
||||||
|
.REGISTER:
|
||||||
|
.byte "Hello", 0xa0
|
||||||
|
.long RegisterTable
|
||||||
|
//push 0x21
|
||||||
|
|
||||||
|
;*/
|
||||||
|
|
||||||
main fun -> sint32
|
main fun -> sint32
|
||||||
text data<sint32> <- "Hello string!\n"
|
//printChar()
|
||||||
|
|
||||||
|
res1 sint32 <- normAdd(4, 5)
|
||||||
|
res2 sint32 <- rawAdd(4, 5)
|
||||||
|
|
||||||
ret 0
|
ret 0
|
||||||
;
|
;
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "Parser/Expression/ExpressionBlock.h"
|
#include "Parser/Expression/ExpressionBlock.h"
|
||||||
|
|
||||||
#include "Parser/Statement/StatementFunction.h"
|
#include "Parser/Statement/StatementFunction.h"
|
||||||
|
#include "Parser/Statement/StatementRawFunction.h"
|
||||||
#include "Parser/Statement/StatementVariable.h"
|
#include "Parser/Statement/StatementVariable.h"
|
||||||
#include "Parser/Statement/StatementAssignment.h"
|
#include "Parser/Statement/StatementAssignment.h"
|
||||||
#include "Parser/Statement/StatementReturn.h"
|
#include "Parser/Statement/StatementReturn.h"
|
||||||
@@ -40,6 +41,12 @@ shared_ptr<llvm::Module> ModuleBuilder::getModule() {
|
|||||||
for (shared_ptr<Statement> &statement : statements)
|
for (shared_ptr<Statement> &statement : statements)
|
||||||
buildStatement(statement);
|
buildStatement(statement);
|
||||||
|
|
||||||
|
// verify module
|
||||||
|
string errorMessage;
|
||||||
|
llvm::raw_string_ostream llvmErrorMessage(errorMessage);
|
||||||
|
if (llvm::verifyModule(*module, &llvmErrorMessage))
|
||||||
|
markError(0, 0, errorMessage);
|
||||||
|
|
||||||
if (!errors.empty()) {
|
if (!errors.empty()) {
|
||||||
for (shared_ptr<Error> &error : errors)
|
for (shared_ptr<Error> &error : errors)
|
||||||
Logger::print(error);
|
Logger::print(error);
|
||||||
@@ -52,7 +59,10 @@ shared_ptr<llvm::Module> ModuleBuilder::getModule() {
|
|||||||
void ModuleBuilder::buildStatement(shared_ptr<Statement> statement) {
|
void ModuleBuilder::buildStatement(shared_ptr<Statement> statement) {
|
||||||
switch (statement->getKind()) {
|
switch (statement->getKind()) {
|
||||||
case StatementKind::FUNCTION:
|
case StatementKind::FUNCTION:
|
||||||
buildFunctionDeclaration(dynamic_pointer_cast<StatementFunction>(statement));
|
buildFunction(dynamic_pointer_cast<StatementFunction>(statement));
|
||||||
|
break;
|
||||||
|
case StatementKind::RAW_FUNCTION:
|
||||||
|
buildRawFunction(dynamic_pointer_cast<StatementRawFunction>(statement));
|
||||||
break;
|
break;
|
||||||
case StatementKind::VARIABLE:
|
case StatementKind::VARIABLE:
|
||||||
buildVarDeclaration(dynamic_pointer_cast<StatementVariable>(statement));
|
buildVarDeclaration(dynamic_pointer_cast<StatementVariable>(statement));
|
||||||
@@ -80,15 +90,15 @@ void ModuleBuilder::buildStatement(shared_ptr<Statement> statement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleBuilder::buildFunctionDeclaration(shared_ptr<StatementFunction> statement) {
|
void ModuleBuilder::buildFunction(shared_ptr<StatementFunction> statement) {
|
||||||
// get argument types
|
// function types
|
||||||
vector<llvm::Type *> types;
|
llvm::Type *returnType = typeForValueType(statement->getReturnValueType());
|
||||||
for (pair<string, shared_ptr<ValueType>> &arg : statement->getArguments()) {
|
vector<llvm::Type *> argTypes;
|
||||||
types.push_back(typeForValueType(arg.second));
|
for (pair<string, shared_ptr<ValueType>> &arg : statement->getArguments())
|
||||||
}
|
argTypes.push_back(typeForValueType(arg.second));
|
||||||
|
|
||||||
// build function declaration
|
// build function declaration
|
||||||
llvm::FunctionType *funType = llvm::FunctionType::get(typeForValueType(statement->getReturnValueType()), types, false);
|
llvm::FunctionType *funType = llvm::FunctionType::get(returnType, argTypes, false);
|
||||||
llvm::Function *fun = llvm::Function::Create(funType, llvm::GlobalValue::ExternalLinkage, statement->getName(), module.get());
|
llvm::Function *fun = llvm::Function::Create(funType, llvm::GlobalValue::ExternalLinkage, statement->getName(), module.get());
|
||||||
if (!setFun(statement->getName(), fun))
|
if (!setFun(statement->getName(), fun))
|
||||||
return;
|
return;
|
||||||
@@ -103,7 +113,7 @@ void ModuleBuilder::buildFunctionDeclaration(shared_ptr<StatementFunction> state
|
|||||||
int i=0;
|
int i=0;
|
||||||
for (auto &arg : fun->args()) {
|
for (auto &arg : fun->args()) {
|
||||||
string name = statement->getArguments()[i].first;
|
string name = statement->getArguments()[i].first;
|
||||||
llvm::Type *type = types[i];
|
llvm::Type *type = argTypes[i];
|
||||||
arg.setName(name);
|
arg.setName(name);
|
||||||
|
|
||||||
llvm::AllocaInst *alloca = builder->CreateAlloca(type, nullptr, name);
|
llvm::AllocaInst *alloca = builder->CreateAlloca(type, nullptr, name);
|
||||||
@@ -126,6 +136,20 @@ void ModuleBuilder::buildFunctionDeclaration(shared_ptr<StatementFunction> state
|
|||||||
markError(0, 0, errorMessage);
|
markError(0, 0, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModuleBuilder::buildRawFunction(shared_ptr<StatementRawFunction> statement) {
|
||||||
|
// function types
|
||||||
|
llvm::Type *returnType = typeForValueType(statement->getReturnValueType());
|
||||||
|
vector<llvm::Type *> argTypes;
|
||||||
|
for (pair<string, shared_ptr<ValueType>> &arg : statement->getArguments())
|
||||||
|
argTypes.push_back(typeForValueType(arg.second));
|
||||||
|
|
||||||
|
// build function declaration & body
|
||||||
|
llvm::FunctionType *funType = llvm::FunctionType::get(returnType, argTypes, false);
|
||||||
|
llvm::InlineAsm *rawFun = llvm::InlineAsm::get(funType, statement->getRawSource(), statement->getConstraints(), true, false, llvm::InlineAsm::AsmDialect::AD_Intel);
|
||||||
|
if (!setRawFun(statement->getName(), rawFun))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void ModuleBuilder::buildVarDeclaration(shared_ptr<StatementVariable> statement) {
|
void ModuleBuilder::buildVarDeclaration(shared_ptr<StatementVariable> statement) {
|
||||||
if (statement->getValueType()->getKind() == ValueTypeKind::DATA) {
|
if (statement->getValueType()->getKind() == ValueTypeKind::DATA) {
|
||||||
vector<llvm::Value *> values = valuesForExpression(statement->getExpression());
|
vector<llvm::Value *> values = valuesForExpression(statement->getExpression());
|
||||||
@@ -481,15 +505,28 @@ llvm::Value *ModuleBuilder::valueForVar(shared_ptr<ExpressionVariable> expressio
|
|||||||
|
|
||||||
llvm::Value *ModuleBuilder::valueForCall(shared_ptr<ExpressionCall> expression) {
|
llvm::Value *ModuleBuilder::valueForCall(shared_ptr<ExpressionCall> expression) {
|
||||||
llvm::Function *fun = getFun(expression->getName());
|
llvm::Function *fun = getFun(expression->getName());
|
||||||
if (fun == nullptr)
|
if (fun != nullptr) {
|
||||||
return nullptr;
|
llvm::FunctionType *funType = fun->getFunctionType();
|
||||||
llvm::FunctionType *funType = fun->getFunctionType();
|
vector<llvm::Value*> argValues;
|
||||||
vector<llvm::Value*> argValues;
|
for (shared_ptr<Expression> &argumentExpression : expression->getArgumentExpressions()) {
|
||||||
for (shared_ptr<Expression> &argumentExpression : expression->getArgumentExpressions()) {
|
llvm::Value *argValue = valueForExpression(argumentExpression);
|
||||||
llvm::Value *argValue = valueForExpression(argumentExpression);
|
argValues.push_back(argValue);
|
||||||
argValues.push_back(argValue);
|
}
|
||||||
|
return builder->CreateCall(funType, fun, llvm::ArrayRef(argValues));
|
||||||
}
|
}
|
||||||
return builder->CreateCall(funType, fun, llvm::ArrayRef(argValues));
|
|
||||||
|
llvm::InlineAsm *rawFun = getRawFun(expression->getName());
|
||||||
|
if (rawFun != nullptr) {
|
||||||
|
vector<llvm::Value *>argValues;
|
||||||
|
for (shared_ptr<Expression> &argumentExpression : expression->getArgumentExpressions()) {
|
||||||
|
llvm::Value *argValue = valueForExpression(argumentExpression);
|
||||||
|
argValues.push_back(argValue);
|
||||||
|
}
|
||||||
|
return builder->CreateCall(rawFun, llvm::ArrayRef(argValues));
|
||||||
|
}
|
||||||
|
|
||||||
|
markError(0, 0, format("Function \"{}\" not defined in scope", expression->getName()));
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleBuilder::setAlloca(string name, llvm::AllocaInst *alloca) {
|
bool ModuleBuilder::setAlloca(string name, llvm::AllocaInst *alloca) {
|
||||||
@@ -518,7 +555,7 @@ llvm::AllocaInst* ModuleBuilder::getAlloca(string name) {
|
|||||||
|
|
||||||
bool ModuleBuilder::setFun(string name, llvm::Function *fun) {
|
bool ModuleBuilder::setFun(string name, llvm::Function *fun) {
|
||||||
if (scopes.top().funMap[name] != nullptr) {
|
if (scopes.top().funMap[name] != nullptr) {
|
||||||
markError(0, 0, format("Function \"{}\" already defined", name));
|
markError(0, 0, format("Function \"{}\" already defined in scope", name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +573,29 @@ llvm::Function* ModuleBuilder::getFun(string name) {
|
|||||||
scopes.pop();
|
scopes.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
markError(0, 0, format("Function \"{}\" not defined in scope", name));
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModuleBuilder::setRawFun(string name, llvm::InlineAsm *rawFun) {
|
||||||
|
if (scopes.top().rawFunMap[name] != nullptr) {
|
||||||
|
markError(0, 0, format("Raw function \"{}\" already defined in scope", name));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
scopes.top().rawFunMap[name] = rawFun;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::InlineAsm *ModuleBuilder::getRawFun(string name) {
|
||||||
|
stack<Scope> scopes = this->scopes;
|
||||||
|
|
||||||
|
while (!scopes.empty()) {
|
||||||
|
llvm::InlineAsm *rawFun = scopes.top().rawFunMap[name];
|
||||||
|
if (rawFun != nullptr)
|
||||||
|
return rawFun;
|
||||||
|
scopes.pop();
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <llvm/IR/Constants.h>
|
#include <llvm/IR/Constants.h>
|
||||||
#include <llvm/Support/raw_ostream.h>
|
#include <llvm/Support/raw_ostream.h>
|
||||||
#include <llvm/IR/Verifier.h>
|
#include <llvm/IR/Verifier.h>
|
||||||
|
#include <llvm/IR/InlineAsm.h>
|
||||||
|
|
||||||
class Error;
|
class Error;
|
||||||
class ValueType;
|
class ValueType;
|
||||||
@@ -26,6 +27,7 @@ enum class ExpressionBinaryOperation;
|
|||||||
|
|
||||||
class Statement;
|
class Statement;
|
||||||
class StatementFunction;
|
class StatementFunction;
|
||||||
|
class StatementRawFunction;
|
||||||
class StatementVariable;
|
class StatementVariable;
|
||||||
class StatementAssignment;
|
class StatementAssignment;
|
||||||
class StatementReturn;
|
class StatementReturn;
|
||||||
@@ -39,6 +41,7 @@ using namespace std;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
map<string, llvm::AllocaInst*> allocaMap;
|
map<string, llvm::AllocaInst*> allocaMap;
|
||||||
map<string, llvm::Function*> funMap;
|
map<string, llvm::Function*> funMap;
|
||||||
|
map<string, llvm::InlineAsm*> rawFunMap;
|
||||||
} Scope;
|
} Scope;
|
||||||
|
|
||||||
class ModuleBuilder {
|
class ModuleBuilder {
|
||||||
@@ -60,7 +63,8 @@ private:
|
|||||||
stack<Scope> scopes;
|
stack<Scope> scopes;
|
||||||
|
|
||||||
void buildStatement(shared_ptr<Statement> statement);
|
void buildStatement(shared_ptr<Statement> statement);
|
||||||
void buildFunctionDeclaration(shared_ptr<StatementFunction> statement);
|
void buildFunction(shared_ptr<StatementFunction> statement);
|
||||||
|
void buildRawFunction(shared_ptr<StatementRawFunction> statement);
|
||||||
void buildVarDeclaration(shared_ptr<StatementVariable> statement);
|
void buildVarDeclaration(shared_ptr<StatementVariable> statement);
|
||||||
void buildAssignment(shared_ptr<StatementAssignment> statement);
|
void buildAssignment(shared_ptr<StatementAssignment> statement);
|
||||||
void buildBlock(shared_ptr<StatementBlock> statement);
|
void buildBlock(shared_ptr<StatementBlock> statement);
|
||||||
@@ -88,6 +92,9 @@ private:
|
|||||||
bool setFun(string name, llvm::Function *fun);
|
bool setFun(string name, llvm::Function *fun);
|
||||||
llvm::Function *getFun(string name);
|
llvm::Function *getFun(string name);
|
||||||
|
|
||||||
|
bool setRawFun(string name, llvm::InlineAsm *rawFun);
|
||||||
|
llvm::InlineAsm *getRawFun(string name);
|
||||||
|
|
||||||
llvm::Type *typeForValueType(shared_ptr<ValueType> valueType, int count = 0);
|
llvm::Type *typeForValueType(shared_ptr<ValueType> valueType, int count = 0);
|
||||||
|
|
||||||
void markError(int line, int column, string message);
|
void markError(int line, int column, string message);
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ vector<shared_ptr<Token>> Lexer::getTokens() {
|
|||||||
currentIndex = 0;
|
currentIndex = 0;
|
||||||
currentLine = 0;
|
currentLine = 0;
|
||||||
currentColumn = 0;
|
currentColumn = 0;
|
||||||
|
foundRawSourceStart = false;
|
||||||
|
isParsingRawSource = false;
|
||||||
|
|
||||||
tokens.clear();
|
tokens.clear();
|
||||||
errors.clear();
|
errors.clear();
|
||||||
@@ -117,6 +119,11 @@ shared_ptr<Token> Lexer::nextToken() {
|
|||||||
return nextToken(); // gets rid of remaining white spaces without repeating the code
|
return nextToken(); // gets rid of remaining white spaces without repeating the code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// raw source
|
||||||
|
token = matchRawSourceLine();
|
||||||
|
if (token != nullptr)
|
||||||
|
return token;
|
||||||
|
|
||||||
// structural
|
// structural
|
||||||
token = match(TokenKind::LEFT_PAREN, "(", false);
|
token = match(TokenKind::LEFT_PAREN, "(", false);
|
||||||
if (token != nullptr)
|
if (token != nullptr)
|
||||||
@@ -213,6 +220,12 @@ shared_ptr<Token> Lexer::nextToken() {
|
|||||||
if (token != nullptr)
|
if (token != nullptr)
|
||||||
return token;
|
return token;
|
||||||
|
|
||||||
|
token = match(TokenKind::RAW_FUNCTION, "raw", true);
|
||||||
|
if (token != nullptr) {
|
||||||
|
foundRawSourceStart = true;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
token = match(TokenKind::RETURN, "ret", true);
|
token = match(TokenKind::RETURN, "ret", true);
|
||||||
if (token != nullptr)
|
if (token != nullptr)
|
||||||
return token;
|
return token;
|
||||||
@@ -271,8 +284,10 @@ shared_ptr<Token> Lexer::nextToken() {
|
|||||||
|
|
||||||
// new line
|
// new line
|
||||||
token = match(TokenKind::NEW_LINE, "\n", false);
|
token = match(TokenKind::NEW_LINE, "\n", false);
|
||||||
if (token != nullptr)
|
if (token != nullptr) {
|
||||||
|
tryStartingRawSourceParsing();
|
||||||
return token;
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
// eof
|
// eof
|
||||||
token = matchEnd();
|
token = matchEnd();
|
||||||
@@ -430,21 +445,6 @@ shared_ptr<Token> Lexer::matchString() {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<Token> Lexer::matchIdentifier() {
|
|
||||||
int nextIndex = currentIndex;
|
|
||||||
|
|
||||||
while (nextIndex < source.length() && isIdentifier(nextIndex))
|
|
||||||
nextIndex++;
|
|
||||||
|
|
||||||
if (nextIndex == currentIndex || !isSeparator(nextIndex))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
string lexme = source.substr(currentIndex, nextIndex - currentIndex);
|
|
||||||
shared_ptr<Token> token = make_shared<Token>(TokenKind::IDENTIFIER, lexme, currentLine, currentColumn);
|
|
||||||
advanceWithToken(token);
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_ptr<Token> Lexer::matchType() {
|
shared_ptr<Token> Lexer::matchType() {
|
||||||
int nextIndex = currentIndex;
|
int nextIndex = currentIndex;
|
||||||
|
|
||||||
@@ -463,6 +463,52 @@ shared_ptr<Token> Lexer::matchType() {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_ptr<Token> Lexer::matchIdentifier() {
|
||||||
|
int nextIndex = currentIndex;
|
||||||
|
|
||||||
|
while (nextIndex < source.length() && isIdentifier(nextIndex))
|
||||||
|
nextIndex++;
|
||||||
|
|
||||||
|
if (nextIndex == currentIndex || !isSeparator(nextIndex))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
string lexme = source.substr(currentIndex, nextIndex - currentIndex);
|
||||||
|
shared_ptr<Token> token = make_shared<Token>(TokenKind::IDENTIFIER, lexme, currentLine, currentColumn);
|
||||||
|
advanceWithToken(token);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lexer::tryStartingRawSourceParsing() {
|
||||||
|
if (!foundRawSourceStart)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!tokens.at(tokens.size() - 1)->isOfKind({TokenKind::COLON, TokenKind::COMMA, TokenKind::RIGHT_ARROW})) {
|
||||||
|
foundRawSourceStart = false;
|
||||||
|
isParsingRawSource = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<Token> Lexer::matchRawSourceLine() {
|
||||||
|
int nextIndex = currentIndex;
|
||||||
|
|
||||||
|
if (!isParsingRawSource)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (source.at(nextIndex) == ';') {
|
||||||
|
isParsingRawSource = false;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (source.at(nextIndex) != '\n')
|
||||||
|
nextIndex++;
|
||||||
|
|
||||||
|
string lexme = source.substr(currentIndex, nextIndex - currentIndex);
|
||||||
|
shared_ptr<Token> token = make_shared<Token>(TokenKind::RAW_SOURCE_LINE, lexme, currentLine, currentColumn);
|
||||||
|
advanceWithToken(token);
|
||||||
|
currentIndex++; // skip newline
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
shared_ptr<Token> Lexer::matchEnd() {
|
shared_ptr<Token> Lexer::matchEnd() {
|
||||||
if (currentIndex >= source.length())
|
if (currentIndex >= source.length())
|
||||||
return make_shared<Token>(TokenKind::END, "", currentLine, currentColumn);
|
return make_shared<Token>(TokenKind::END, "", currentLine, currentColumn);
|
||||||
@@ -530,11 +576,15 @@ bool Lexer::isSeparator(int index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Lexer::advanceWithToken(shared_ptr<Token> token) {
|
void Lexer::advanceWithToken(shared_ptr<Token> token) {
|
||||||
if (token->getKind() == TokenKind::NEW_LINE) {
|
switch (token->getKind()) {
|
||||||
currentLine++;
|
case TokenKind::NEW_LINE:
|
||||||
currentColumn = 0;
|
case TokenKind::RAW_SOURCE_LINE:
|
||||||
} else {
|
currentLine++;
|
||||||
currentColumn += token->getLexme().length();
|
currentColumn = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
currentColumn += token->getLexme().length();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
currentIndex += token->getLexme().length();
|
currentIndex += token->getLexme().length();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ private:
|
|||||||
int currentColumn;
|
int currentColumn;
|
||||||
vector<shared_ptr<Token>> tokens;
|
vector<shared_ptr<Token>> tokens;
|
||||||
vector<shared_ptr<Error>> errors;
|
vector<shared_ptr<Error>> errors;
|
||||||
|
bool foundRawSourceStart;
|
||||||
|
bool isParsingRawSource;
|
||||||
|
|
||||||
shared_ptr<Token> nextToken();
|
shared_ptr<Token> nextToken();
|
||||||
shared_ptr<Token> match(TokenKind kind, string lexme, bool needsSeparator);
|
shared_ptr<Token> match(TokenKind kind, string lexme, bool needsSeparator);
|
||||||
@@ -28,6 +30,8 @@ private:
|
|||||||
shared_ptr<Token> matchString();
|
shared_ptr<Token> matchString();
|
||||||
shared_ptr<Token> matchType();
|
shared_ptr<Token> matchType();
|
||||||
shared_ptr<Token> matchIdentifier();
|
shared_ptr<Token> matchIdentifier();
|
||||||
|
void tryStartingRawSourceParsing();
|
||||||
|
shared_ptr<Token> matchRawSourceLine();
|
||||||
shared_ptr<Token> matchEnd();
|
shared_ptr<Token> matchEnd();
|
||||||
|
|
||||||
bool isWhiteSpace(int index);
|
bool isWhiteSpace(int index);
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ enum class TokenKind {
|
|||||||
RIGHT_ARROW,
|
RIGHT_ARROW,
|
||||||
|
|
||||||
FUNCTION,
|
FUNCTION,
|
||||||
|
RAW_FUNCTION,
|
||||||
|
RAW_SOURCE_LINE,
|
||||||
RETURN,
|
RETURN,
|
||||||
REPEAT,
|
REPEAT,
|
||||||
IF,
|
IF,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "Parser/Statement/StatementMetaExternFunction.h"
|
#include "Parser/Statement/StatementMetaExternFunction.h"
|
||||||
#include "Parser/Statement/StatementVariable.h"
|
#include "Parser/Statement/StatementVariable.h"
|
||||||
#include "Parser/Statement/StatementFunction.h"
|
#include "Parser/Statement/StatementFunction.h"
|
||||||
|
#include "Parser/Statement/StatementRawFunction.h"
|
||||||
#include "Parser/Statement/StatementBlock.h"
|
#include "Parser/Statement/StatementBlock.h"
|
||||||
#include "Parser/Statement/StatementAssignment.h"
|
#include "Parser/Statement/StatementAssignment.h"
|
||||||
#include "Parser/Statement/StatementReturn.h"
|
#include "Parser/Statement/StatementReturn.h"
|
||||||
@@ -97,6 +98,10 @@ string Logger::toString(shared_ptr<Token> token) {
|
|||||||
return "ELSE";
|
return "ELSE";
|
||||||
case TokenKind::FUNCTION:
|
case TokenKind::FUNCTION:
|
||||||
return "FUN";
|
return "FUN";
|
||||||
|
case TokenKind::RAW_FUNCTION:
|
||||||
|
return "RAW";
|
||||||
|
case TokenKind::RAW_SOURCE_LINE:
|
||||||
|
return format("RAW_SOURCE_LINE({})", token->getLexme());
|
||||||
case TokenKind::RETURN:
|
case TokenKind::RETURN:
|
||||||
return "RET";
|
return "RET";
|
||||||
case TokenKind::REPEAT:
|
case TokenKind::REPEAT:
|
||||||
@@ -179,6 +184,8 @@ string Logger::toString(TokenKind tokenKind) {
|
|||||||
return "ELSE";
|
return "ELSE";
|
||||||
case TokenKind::FUNCTION:
|
case TokenKind::FUNCTION:
|
||||||
return "FUN";
|
return "FUN";
|
||||||
|
case TokenKind::RAW_FUNCTION:
|
||||||
|
return "RAW";
|
||||||
case TokenKind::RETURN:
|
case TokenKind::RETURN:
|
||||||
return "RET";
|
return "RET";
|
||||||
case TokenKind::REPEAT:
|
case TokenKind::REPEAT:
|
||||||
@@ -217,6 +224,8 @@ string Logger::toString(shared_ptr<Statement> statement) {
|
|||||||
return toString(dynamic_pointer_cast<StatementVariable>(statement));
|
return toString(dynamic_pointer_cast<StatementVariable>(statement));
|
||||||
case StatementKind::FUNCTION:
|
case StatementKind::FUNCTION:
|
||||||
return toString(dynamic_pointer_cast<StatementFunction>(statement));
|
return toString(dynamic_pointer_cast<StatementFunction>(statement));
|
||||||
|
case StatementKind::RAW_FUNCTION:
|
||||||
|
return toString(dynamic_pointer_cast<StatementRawFunction>(statement));
|
||||||
case StatementKind::BLOCK:
|
case StatementKind::BLOCK:
|
||||||
return toString(dynamic_pointer_cast<StatementBlock>(statement));
|
return toString(dynamic_pointer_cast<StatementBlock>(statement));
|
||||||
case StatementKind::ASSIGNMENT:
|
case StatementKind::ASSIGNMENT:
|
||||||
@@ -262,6 +271,21 @@ string Logger::toString(shared_ptr<StatementFunction> statement) {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string Logger::toString(shared_ptr<StatementRawFunction> statement) {
|
||||||
|
string text;
|
||||||
|
|
||||||
|
string argsString;
|
||||||
|
for (int i = 0; i < statement->getArguments().size(); i++) {
|
||||||
|
auto arg = statement->getArguments().at(i);
|
||||||
|
argsString += format("ARG({}, {})", arg.first, toString(arg.second));
|
||||||
|
}
|
||||||
|
text += format("RAW(\"{}\"|{}|{}):\n", statement->getName(), argsString, toString(statement->getReturnValueType()));
|
||||||
|
|
||||||
|
text += statement->getRawSource();
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
string Logger::toString(shared_ptr<StatementBlock> statement) {
|
string Logger::toString(shared_ptr<StatementBlock> statement) {
|
||||||
string text;
|
string text;
|
||||||
|
|
||||||
@@ -468,13 +492,13 @@ void Logger::print(shared_ptr<Error> error) {
|
|||||||
|
|
||||||
if (expectedTokenKind) {
|
if (expectedTokenKind) {
|
||||||
message = format(
|
message = format(
|
||||||
"Expected token {} but instead found \"{}\" at line: {}, column: {}",
|
"Expected token {} but instead found {} at line: {}, column: {}",
|
||||||
toString(*expectedTokenKind), token->getLexme(), token->getLine() + 1, token->getColumn() + 1
|
toString(*expectedTokenKind), toString(token), token->getLine() + 1, token->getColumn() + 1
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
message = format(
|
message = format(
|
||||||
"Unexpected token \"{}\" found at line: {}, column: {}",
|
"Unexpected token \"{}\" found at line: {}, column: {}",
|
||||||
token->getLexme(), token->getLine() + 1, token->getColumn() + 1
|
toString(token), token->getLine() + 1, token->getColumn() + 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (errorMessage)
|
if (errorMessage)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class Statement;
|
|||||||
class StatementMetaExternFunction;
|
class StatementMetaExternFunction;
|
||||||
class StatementVariable;
|
class StatementVariable;
|
||||||
class StatementFunction;
|
class StatementFunction;
|
||||||
|
class StatementRawFunction;
|
||||||
class StatementBlock;
|
class StatementBlock;
|
||||||
class StatementAssignment;
|
class StatementAssignment;
|
||||||
class StatementReturn;
|
class StatementReturn;
|
||||||
@@ -41,6 +42,7 @@ private:
|
|||||||
static string toString(shared_ptr<StatementMetaExternFunction> statement);
|
static string toString(shared_ptr<StatementMetaExternFunction> statement);
|
||||||
static string toString(shared_ptr<StatementVariable> statement);
|
static string toString(shared_ptr<StatementVariable> statement);
|
||||||
static string toString(shared_ptr<StatementFunction> statement);
|
static string toString(shared_ptr<StatementFunction> statement);
|
||||||
|
static string toString(shared_ptr<StatementRawFunction> statement);
|
||||||
static string toString(shared_ptr<StatementBlock> statement);
|
static string toString(shared_ptr<StatementBlock> statement);
|
||||||
static string toString(shared_ptr<StatementAssignment> statement);
|
static string toString(shared_ptr<StatementAssignment> statement);
|
||||||
static string toString(shared_ptr<StatementReturn> statement);
|
static string toString(shared_ptr<StatementReturn> statement);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "Parser/Expression/ExpressionBlock.h"
|
#include "Parser/Expression/ExpressionBlock.h"
|
||||||
|
|
||||||
#include "Parser/Statement/StatementFunction.h"
|
#include "Parser/Statement/StatementFunction.h"
|
||||||
|
#include "Parser/Statement/StatementRawFunction.h"
|
||||||
#include "Parser/Statement/StatementVariable.h"
|
#include "Parser/Statement/StatementVariable.h"
|
||||||
#include "Parser/Statement/StatementAssignment.h"
|
#include "Parser/Statement/StatementAssignment.h"
|
||||||
#include "Parser/Statement/StatementReturn.h"
|
#include "Parser/Statement/StatementReturn.h"
|
||||||
@@ -61,6 +62,10 @@ shared_ptr<Statement> Parser::nextStatement() {
|
|||||||
if (statement != nullptr || errors.size() > errorsCount)
|
if (statement != nullptr || errors.size() > errorsCount)
|
||||||
return statement;
|
return statement;
|
||||||
|
|
||||||
|
statement = matchStatementRawFunction();
|
||||||
|
if (statement != nullptr || errors.size() > errorsCount)
|
||||||
|
return statement;
|
||||||
|
|
||||||
statement = matchStatementVariable();
|
statement = matchStatementVariable();
|
||||||
if (statement != nullptr || errors.size() > errorsCount)
|
if (statement != nullptr || errors.size() > errorsCount)
|
||||||
return statement;
|
return statement;
|
||||||
@@ -230,6 +235,87 @@ shared_ptr<Statement> Parser::matchStatementFunction() {
|
|||||||
return make_shared<StatementFunction>(name, arguments, returnType, dynamic_pointer_cast<StatementBlock>(statementBlock));
|
return make_shared<StatementFunction>(name, arguments, returnType, dynamic_pointer_cast<StatementBlock>(statementBlock));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_ptr<Statement> Parser::matchStatementRawFunction() {
|
||||||
|
if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::RAW_FUNCTION}, true, false))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
string name;
|
||||||
|
string constraints;
|
||||||
|
vector<pair<string, shared_ptr<ValueType>>> arguments;
|
||||||
|
shared_ptr<ValueType> returnType = ValueType::NONE;
|
||||||
|
string rawSource;
|
||||||
|
|
||||||
|
// name
|
||||||
|
name = tokens.at(currentIndex++)->getLexme();
|
||||||
|
currentIndex++; // skip raw
|
||||||
|
|
||||||
|
// constraints
|
||||||
|
|
||||||
|
if (tryMatchingTokenKinds({TokenKind::LESS}, true, true)) {
|
||||||
|
if (tokens.at(currentIndex)->isOfKind({TokenKind::STRING})) {
|
||||||
|
constraints = tokens.at(currentIndex++)->getLexme();
|
||||||
|
// remove enclosing quotes
|
||||||
|
if (constraints.length() >= 2)
|
||||||
|
constraints = constraints.substr(1, constraints.length() - 2);
|
||||||
|
}
|
||||||
|
if (!tryMatchingTokenKinds({TokenKind::GREATER}, true, true))
|
||||||
|
markError({TokenKind::GREATER}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// arguments
|
||||||
|
if (tryMatchingTokenKinds({TokenKind::COLON}, true, true)) {
|
||||||
|
do {
|
||||||
|
tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // skip new line
|
||||||
|
if (!tryMatchingTokenKinds({TokenKind::IDENTIFIER, TokenKind::TYPE}, true, false)) {
|
||||||
|
markError({}, "Expected function argument");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
shared_ptr<Token> identifierToken = tokens.at(currentIndex++);
|
||||||
|
shared_ptr<ValueType> argumentType = matchValueType();
|
||||||
|
if (argumentType == nullptr) {
|
||||||
|
markError(TokenKind::TYPE, {});
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments.push_back(pair<string, shared_ptr<ValueType>>(identifierToken->getLexme(), argumentType));
|
||||||
|
} while (tryMatchingTokenKinds({TokenKind::COMMA}, true, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// return type
|
||||||
|
if (tryMatchingTokenKinds({TokenKind::RIGHT_ARROW}, true, true)) {
|
||||||
|
tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true); // skip new line
|
||||||
|
|
||||||
|
returnType = matchValueType();
|
||||||
|
if (returnType == nullptr) {
|
||||||
|
markError(TokenKind::TYPE, {});
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume new line
|
||||||
|
if (!tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true)) {
|
||||||
|
markError(TokenKind::NEW_LINE, {});
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// source
|
||||||
|
while (tryMatchingTokenKinds({TokenKind::RAW_SOURCE_LINE}, true, false)) {
|
||||||
|
if (!rawSource.empty())
|
||||||
|
rawSource += "\n";
|
||||||
|
rawSource += tokens.at(currentIndex++)->getLexme();
|
||||||
|
|
||||||
|
// Consume optional new line (for example because of a comment)
|
||||||
|
tryMatchingTokenKinds({TokenKind::NEW_LINE}, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!tryMatchingTokenKinds({TokenKind::SEMICOLON}, false, true)) {
|
||||||
|
markError(TokenKind::SEMICOLON, {});
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return make_shared<StatementRawFunction>(name, constraints, arguments, returnType, rawSource);
|
||||||
|
}
|
||||||
|
|
||||||
shared_ptr<Statement> Parser::matchStatementBlock(vector<TokenKind> terminalTokenKinds) {
|
shared_ptr<Statement> Parser::matchStatementBlock(vector<TokenKind> terminalTokenKinds) {
|
||||||
vector<shared_ptr<Statement>> statements;
|
vector<shared_ptr<Statement>> statements;
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ private:
|
|||||||
shared_ptr<Statement> matchStatementMetaExternFunction();
|
shared_ptr<Statement> matchStatementMetaExternFunction();
|
||||||
shared_ptr<Statement> matchStatementVariable();
|
shared_ptr<Statement> matchStatementVariable();
|
||||||
shared_ptr<Statement> matchStatementFunction();
|
shared_ptr<Statement> matchStatementFunction();
|
||||||
|
shared_ptr<Statement> matchStatementRawFunction();
|
||||||
|
|
||||||
shared_ptr<Statement> matchStatementBlock(vector<TokenKind> terminalTokenKinds);
|
shared_ptr<Statement> matchStatementBlock(vector<TokenKind> terminalTokenKinds);
|
||||||
shared_ptr<Statement> matchStatementAssignment();
|
shared_ptr<Statement> matchStatementAssignment();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ enum class StatementKind {
|
|||||||
BLOCK,
|
BLOCK,
|
||||||
RETURN,
|
RETURN,
|
||||||
FUNCTION,
|
FUNCTION,
|
||||||
|
RAW_FUNCTION,
|
||||||
VARIABLE,
|
VARIABLE,
|
||||||
ASSIGNMENT,
|
ASSIGNMENT,
|
||||||
REPEAT,
|
REPEAT,
|
||||||
|
|||||||
24
src/Parser/Statement/StatementRawFunction.cpp
Normal file
24
src/Parser/Statement/StatementRawFunction.cpp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#include "StatementRawFunction.h"
|
||||||
|
|
||||||
|
StatementRawFunction::StatementRawFunction(string name, string constraints, vector<pair<string, shared_ptr<ValueType>>> arguments, shared_ptr<ValueType> returnValueType, string rawSource):
|
||||||
|
Statement(StatementKind::RAW_FUNCTION), name(name), constraints(constraints), arguments(arguments), returnValueType(returnValueType), rawSource(rawSource) { }
|
||||||
|
|
||||||
|
string StatementRawFunction::getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
string StatementRawFunction::getConstraints() {
|
||||||
|
return constraints;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<pair<string, shared_ptr<ValueType>>> StatementRawFunction::getArguments() {
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<ValueType> StatementRawFunction::getReturnValueType() {
|
||||||
|
return returnValueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
string StatementRawFunction::getRawSource() {
|
||||||
|
return rawSource;
|
||||||
|
}
|
||||||
20
src/Parser/Statement/StatementRawFunction.h
Normal file
20
src/Parser/Statement/StatementRawFunction.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include "Parser/Statement/Statement.h"
|
||||||
|
|
||||||
|
class ValueType;
|
||||||
|
|
||||||
|
class StatementRawFunction: public Statement {
|
||||||
|
private:
|
||||||
|
string name;
|
||||||
|
string constraints;
|
||||||
|
vector<pair<string, shared_ptr<ValueType>>> arguments;
|
||||||
|
shared_ptr<ValueType> returnValueType;
|
||||||
|
string rawSource;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StatementRawFunction(string name, string constraints, vector<pair<string, shared_ptr<ValueType>>> arguments, shared_ptr<ValueType> returnValueType, string rawSource);
|
||||||
|
string getName();
|
||||||
|
string getConstraints();
|
||||||
|
vector<pair<string, shared_ptr<ValueType>>> getArguments();
|
||||||
|
shared_ptr<ValueType> getReturnValueType();
|
||||||
|
string getRawSource();
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user