Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement function to get value from environemt via $ or ${} #19

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CoreVM/transform/MergeBlockPass.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
module;

#include <cstdio>
#include <list>

module CoreVM;
Expand Down
17 changes: 17 additions & 0 deletions src/shell/AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,22 @@ struct BuiltinSetStmt final: public Statement
void accept(Visitor& visitor) const override { visitor.visit(*this); }
};


struct VariableSubstExpr final: public Statement
{
std::reference_wrapper<CoreVM::NativeCallback const> callback;
std::unique_ptr<Expr> name;

VariableSubstExpr(std::reference_wrapper<CoreVM::NativeCallback const> callback,
std::unique_ptr<Expr> name):
callback { callback }, name {std::move( name )}
{
}

void accept(Visitor& visitor) const override { visitor.visit(*this); }
};


struct BuiltinChDirStmt final: public Statement
{
std::reference_wrapper<CoreVM::NativeCallback const> callback;
Expand Down Expand Up @@ -217,6 +233,7 @@ struct SubstitutionExpr final: public Expr
{
std::unique_ptr<Statement> pipeline;

SubstitutionExpr(std::unique_ptr<Statement> pipeline): pipeline(std::move(pipeline)) {}
void accept(Visitor& visitor) const override { visitor.visit(*this); }
};

Expand Down
15 changes: 13 additions & 2 deletions src/shell/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
module;
#include <shell/AST.h>
#include <shell/Visitor.h>
#include <fmt/format.h>

#include <crispy/assert.h>

#include <fmt/format.h>

import Lexer;

export module ASTPrinter;
Expand Down Expand Up @@ -90,6 +91,16 @@ export class ASTPrinter: public Visitor
}
}

void visit(VariableSubstExpr const& node) override
{
_result += "getenv";
if (node.name)
{
_result += ' ';
node.name->accept(*this);
}
}

void visit(BuiltinExitStmt const& node) override
{
_result += "exit";
Expand Down Expand Up @@ -146,7 +157,7 @@ export class ASTPrinter: public Visitor
}

void visit(LiteralExpr const& node) override { _result += fmt::format("{}", node.value); }
void visit(SubstitutionExpr const& node) override { crispy::ignore_unused(node); }
void visit(SubstitutionExpr const& node) override { node.pipeline->accept(*this); }
void visit(CommandFileSubst const& node) override { crispy::ignore_unused(node); }
};

Expand Down
16 changes: 13 additions & 3 deletions src/shell/IRGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,24 @@ export class IRGenerator final: public CoreVM::IRBuilder, public ast::Visitor
auto callArguments = std::vector<CoreVM::Value*> {};
if (node.name && node.value)
{

callArguments.push_back(codegen(node.name.get()));
callArguments.push_back(codegen(node.value.get()));
}

_result = createCallFunction(getBuiltinFunction(node.callback.get()), callArguments, "set");
}

void visit(ast::VariableSubstExpr const& node) override
{
auto callArguments = std::vector<CoreVM::Value*> {};
if (node.name )
{
callArguments.push_back(codegen(node.name.get()));
}

_result = createCallFunction(getBuiltinFunction(node.callback.get()), callArguments, "getenv");
}

void visit(ast::BuiltinFalseStmt const&) override { _result = get(CoreVM::CoreNumber(1)); }

void visit(ast::BuiltinReadStmt const& node) override
Expand Down Expand Up @@ -209,9 +219,9 @@ export class IRGenerator final: public CoreVM::IRBuilder, public ast::Visitor
_result = createCallFunction(getBuiltinFunction(node.callback.get()), callArguments, "callProcess");
}

void visit(ast::SubstitutionExpr const&) override
void visit(ast::SubstitutionExpr const& node) override
{
// TODO
node.pipeline->accept(*this);
}
void visit(ast::WhileStmt const& node) override
{
Expand Down
87 changes: 57 additions & 30 deletions src/shell/Lexer.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
// SPDX-License-Identifier: Apache-2.0
module;

#include <fmt/format.h>
#include <crispy/logstore.h>

#include <fmt/format.h>

#include <cstring>
#include <memory>
#include <string>
#include <string_view>
#include <vector>


auto inline lexerLog = logstore::category("lexer ", "Lexer logger ", logstore::category::state::Enabled );
auto inline lexerLog = logstore::category("lexer ", "Lexer logger", logstore::category::state::Enabled);

using namespace std::string_view_literals;

Expand Down Expand Up @@ -146,6 +147,13 @@ export class StringSource final: public Source

export class Lexer
{

template <typename... T>
void trace(std::string info, T... args)
{
fmt::print(fmt::runtime("Lexer: " + info), args...);
}

public:
explicit Lexer(std::unique_ptr<Source> source): _source { std::move(source) }
{
Expand Down Expand Up @@ -201,6 +209,8 @@ export class Lexer
return consumeCharAndConfirmToken(Token::DollarNot);
else if (_currentChar == '?')
return consumeCharAndConfirmToken(Token::DollarQuestion);
else if (_currentChar == '{')
return consumeIdentifierInsideBracket(Token::DollarName);
else if (_currentChar < 0x80 && std::isalpha(static_cast<char>(_currentChar)))
return consumeIdentifier(Token::DollarName);
else if (_currentChar < 0x80 && std::isdigit(static_cast<char>(_currentChar)))
Expand Down Expand Up @@ -235,18 +245,19 @@ export class Lexer
}

static std::vector<TokenInfo> tokenize(std::unique_ptr<Source> source)
{
auto tokens = std::vector<TokenInfo> {};
auto lexer = Lexer { std::move(source) };

while (lexer.currentToken() != Token::EndOfInput)
{
tokens.emplace_back(TokenInfo { lexer.currentToken(), lexer.currentLiteral(), lexer.currentRange() });
lexer.nextToken();
}
auto tokens = std::vector<TokenInfo> {};
auto lexer = Lexer { std::move(source) };

return tokens;
}
while (lexer.currentToken() != Token::EndOfInput)
{
tokens.emplace_back(
TokenInfo { lexer.currentToken(), lexer.currentLiteral(), lexer.currentRange() });
lexer.nextToken();
}

return tokens;
}

private:
[[nodiscard]] bool eof() const noexcept { return _currentChar == char32_t(-1); }
Expand Down Expand Up @@ -278,6 +289,23 @@ export class Lexer

Token consumeIdentifier() { return consumeIdentifier(Token::Identifier); }

Token consumeIdentifierInsideBracket(Token token)
{
auto constexpr ReservedSymbols = U"|<>()[]!$'\"\t\r\n ;"sv;
int countBracket = 0;
while (!eof() && ReservedSymbols.find(_currentChar) == std::string_view::npos)
{
trace("consumeIdentifier: '{}'\n", (char) _currentChar);
if (_currentChar != '{' && _currentChar != '}')
_nextToken.literal += static_cast<char>(_currentChar); // TODO: UTF-8
nextChar();
}
if (countBracket != 0)
trace("not balanced brackets \n"); // TODO
trace("consumeIdentifier: result: '{}'\n", _nextToken.literal);
return confirmToken(token);
}

Token consumeIdentifier(Token token)
{
auto constexpr ReservedSymbols = U"|<>()[]{}!$'\"\t\r\n ;"sv;
Expand Down Expand Up @@ -315,26 +343,27 @@ export class Lexer
}

Token consumeCharAndConfirmToken(Token token)
{
nextChar();
return confirmToken(token);
}
{
nextChar();
return confirmToken(token);
}

Token confirmToken(Token token)
{
_nextToken.token = token;
_nextToken.literal = _nextToken.literal;
auto const [a, b, _] = _source->currentSourceLocation();
_nextToken.location.end = { .line = a, .column = b };
_currentToken = _nextToken;
{
_nextToken.token = token;
_nextToken.literal = _nextToken.literal;
auto const [a, b, _] = _source->currentSourceLocation();
_nextToken.location.end = { .line = a, .column = b };
_currentToken = _nextToken;

_nextToken.literal = {};
_nextToken.location.name = _source->currentSourceLocation().name;
_nextToken.location.begin = _nextToken.location.end;
trace("Token is ready : {} \n", _currentToken);

return token;
}
_nextToken.literal = {};
_nextToken.location.name = _source->currentSourceLocation().name;
_nextToken.location.begin = _nextToken.location.end;

return token;
}

std::unique_ptr<Source> _source;
char32_t _currentChar = 0;
Expand All @@ -344,8 +373,6 @@ export class Lexer
};
} // namespace endo



template <>
struct fmt::formatter<endo::LineColumn>: fmt::formatter<std::string>
{
Expand Down
29 changes: 27 additions & 2 deletions src/shell/Lexer_test.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// SPDX-License-Identifier: Apache-2.0
#include <catch2/catch.hpp>

#include <fmt/core.h>
import Lexer;

TEST_CASE("Lexer.basic")
{
auto lexer = endo::Lexer(std::make_unique<endo::StringSource>("echo hello world $PATH"));
auto lexer = endo::Lexer(std::make_unique<endo::StringSource>("echo hello world $PATH ${PATH}"));
CHECK(lexer.currentToken() == endo::Token::Identifier);
CHECK(lexer.currentLiteral() == "echo");

Expand All @@ -21,6 +21,31 @@ TEST_CASE("Lexer.basic")
CHECK(lexer.currentToken() == endo::Token::DollarName);
CHECK(lexer.currentLiteral() == "PATH");

lexer.nextToken();
CHECK(lexer.currentToken() == endo::Token::DollarName);
CHECK(lexer.currentLiteral() == "PATH");

lexer.nextToken();
CHECK(lexer.currentToken() == endo::Token::EndOfInput);
}


TEST_CASE("Lexer.brackets")
{
auto lexer = endo::Lexer(std::make_unique<endo::StringSource>("$PATH ${PATH} ${{PATH}} "));
Yaraslaut marked this conversation as resolved.
Show resolved Hide resolved

CHECK(lexer.currentToken() == endo::Token::DollarName);
CHECK(lexer.currentLiteral() == "PATH");


lexer.nextToken();
CHECK(lexer.currentToken() == endo::Token::DollarName);
CHECK(lexer.currentLiteral() == "PATH");

lexer.nextToken();
CHECK(lexer.currentToken() == endo::Token::DollarName);
CHECK(lexer.currentLiteral() == "PATH");

lexer.nextToken();
CHECK(lexer.currentToken() == endo::Token::EndOfInput);
}
14 changes: 13 additions & 1 deletion src/shell/Parser.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
module;

#include <shell/ScopedLogger.h>
#include <shell/AST.h>
#include <shell/ScopedLogger.h>

#include <crispy/utils.h>
#include <crispy/logstore.h>
Expand Down Expand Up @@ -89,6 +89,12 @@ export class Parser
TRACE_SCOPE("parseStmt");
switch (_lexer.currentToken())
{
case Token::DollarName: {
auto name = std::make_unique<ast::LiteralExpr>(_lexer.currentLiteral());
_lexer.nextToken();
return std::make_unique<ast::VariableSubstExpr>(*_runtime.find("getenv(S)S"),
std::move(name));
}
case Token::String:
case Token::Identifier:
if (_lexer.isDirective("if"))
Expand Down Expand Up @@ -286,6 +292,12 @@ export class Parser
case Token::String:
case Token::Number:
case Token::Identifier: return std::make_unique<ast::LiteralExpr>(consumeLiteral()); break;
case Token::DollarName: {
auto name = std::make_unique<ast::LiteralExpr>(consumeLiteral());
return std::make_unique<ast::SubstitutionExpr>(
std::make_unique<ast::VariableSubstExpr>(*_runtime.find("getenv(S)S"), std::move(name)));
}
break;
default: _report.syntaxError(CoreVM::SourceLocation(), "Expected parameter"); return nullptr;
}
}
Expand Down
15 changes: 15 additions & 0 deletions src/shell/Shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,12 @@ export class Shell final: public CoreVM::Runtime
.returnType(CoreVM::LiteralType::Boolean)
.bind(&Shell::builtinSet, this);

registerFunction("getenv")
.param<std::string>("name")
.returnType(CoreVM::LiteralType::String)
.bind(&Shell::builtinVariableSubst, this);


registerFunction("callproc")
.param<std::vector<std::string>>("args")
//.param<std::vector<CoreVM::CoreNumber>>("redirects")
Expand Down Expand Up @@ -529,6 +535,15 @@ export class Shell final: public CoreVM::Runtime
_env.set(context.getString(1), context.getString(2));
context.setResult(true);
}
void builtinVariableSubst(CoreVM::Params& context)
{
auto res = _env.get(context.getString(1));
if(res.has_value())
context.setResult(std::string(res.value()));
else {
context.setResult("Variable does not exist");
}
}
void builtinSetAndExport(CoreVM::Params& context)
{
_env.set(context.getString(1), context.getString(2));
Expand Down
Loading
Loading