Skip to content

Commit

Permalink
nixd/eval: init (#356)
Browse files Browse the repository at this point in the history
The goal of this PR is to verify the system basically works, like
evaluate a simple "ExprInt".

Not all expressions have been supported yet.
  • Loading branch information
inclyc authored Mar 14, 2024
2 parents eb40e5b + b122cab commit 5f134ea
Show file tree
Hide file tree
Showing 62 changed files with 1,569 additions and 518 deletions.
44 changes: 44 additions & 0 deletions libbc/include/bc/Read.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include <cassert>
#include <cstring>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>

namespace bc {

template <class T> void readBytecode(std::string_view &Data, T &Obj) {
static_assert(!std::is_same_v<T, T>,
"No readBytecode implementation for this type");
}

/// \brief Basic primitives. Deocde from bytes by `memcpy`.
template <class T>
requires std::is_standard_layout_v<T> && std::is_trivial_v<T>
void readBytecode(std::string_view &Data, T &Obj) {
assert(Data.size() >= sizeof(T));
std::memcpy(&Obj, Data.begin(), sizeof(T));
Data = Data.substr(sizeof(T));
}

template <class T>
void readBytecode(std::string_view &Data, std::vector<T> &Obj) {
size_t Size;
readBytecode(Data, Size);
Obj.resize(Size);
for (auto &E : Obj)
readBytecode(Data, E);
}

template <>
void readBytecode<std::string>(std::string_view &Data, std::string &Obj);

template <class T> T eat(std::string_view &Data) {
T Obj;
readBytecode(Data, Obj);
return Obj;
}

} // namespace bc
28 changes: 28 additions & 0 deletions libbc/include/bc/Write.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <ostream>
#include <sstream>
#include <type_traits>

namespace bc {

/// \brief Basic primitives. Trivial data types are just written to a stream.
template <class T>
requires std::is_standard_layout_v<T> && std::is_trivial_v<T>
void writeBytecode(std::ostream &OS, const T &Data) {
OS.write(reinterpret_cast<const char *>(&Data), sizeof(T));
}

void writeBytecode(std::ostream &OS, const std::string_view &Data);

inline void writeBytecode(std::ostream &OS, const std::string &Data) {
writeBytecode(OS, std::string_view(Data));
}

template <class T> std::string toBytecode(const T &Data) {
std::ostringstream OS;
writeBytecode(OS, Data);
return OS.str();
}

} // namespace bc
15 changes: 15 additions & 0 deletions libbc/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
libbc_inc = include_directories('include')

libbc_lib = library(
'bc',
'src/Read.cpp',
'src/Write.cpp',
include_directories: libbc_inc,
)

libbc = declare_dependency(
include_directories: libbc_inc,
link_with: libbc_lib,
)

install_subdir('include/bc', install_dir: 'include')
14 changes: 14 additions & 0 deletions libbc/src/Read.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "bc/Read.h"

namespace bc {

template <>
void readBytecode<std::string>(std::string_view &Data, std::string &Obj) {
size_t Size;
readBytecode(Data, Size);
Obj.resize(Size);
std::memcpy(Obj.data(), Data.data(), Size);
Data = Data.substr(Size);
}

} // namespace bc
10 changes: 10 additions & 0 deletions libbc/src/Write.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "bc/Write.h"

namespace bc {

void writeBytecode(std::ostream &OS, const std::string_view &Data) {
writeBytecode(OS, static_cast<std::size_t>(Data.size()));
OS.write(Data.data(), static_cast<std::streamsize>(Data.size()));
}

} // namespace bc
20 changes: 20 additions & 0 deletions libnixbc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# libnixbc

Defines general bytecode for nix AST.
This is used for nix-interop, with C++ evaluator, thus the node definition is targeted for C++ types.


## The format


All AST nodes are encoded in a compact binary format.
The entire AST is serialized into into a form similar to [S-expression](https://en.wikipedia.org/wiki/S-expression).


### Node Format

| Field Name | Byte Size
|:-:|:-:|
| Pointer | Pointer Size
| Kind | 4
| Payloads | N/A
16 changes: 16 additions & 0 deletions libnixbc/include/nixbc/FileHeader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include "Origin.h"

#include <cstdint>

namespace nixbc {

struct FileHeader {
static constexpr int MagicValue = 0x72A17086;
uint32_t Magic;
uint32_t Version;
/* Origin */
};

} // namespace nixbc
40 changes: 40 additions & 0 deletions libnixbc/include/nixbc/Nodes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once

#include <cstdint>

namespace nixbc {

enum ExprKind : int32_t {
EK_Assert,
EK_Attrs,
EK_Call,
EK_ConcatStrings,
EK_Float,
EK_If,
EK_Int,
EK_Lambda,
EK_Let,
EK_List,
EK_OpAnd,
EK_OpConcatLists,
EK_OpEq,
EK_OpHasAttr,
EK_OpImpl,
EK_OpNEq,
EK_OpNot,
EK_OpOr,
EK_OpUpdate,
EK_Path,
EK_Pos,
EK_Select,
EK_String,
EK_Var,
EK_With,
};

struct NodeHeader {
ExprKind Kind;
uintptr_t Handle;
};

} // namespace nixbc
56 changes: 56 additions & 0 deletions libnixbc/include/nixbc/Origin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#pragma once

#include <bc/Read.h>

#include <cstdint>
#include <string>

namespace nixbc {

class Origin {
public:
/// \brief Origin kind.
///
/// \note Nix interpreter may read the file, or try to read source code for
/// diagnostics reporting.
enum OriginKind : uint8_t {
/// None.
OK_None,

/// Standard input.
OK_Stdin,

/// \p EvalState::parseExprFromString()
OK_String,

/// \p EvalState::parseExprFromFile()
OK_Path,
};

private:
OriginKind Kind;

protected:
Origin(OriginKind Kind) : Kind(Kind) {}

public:
[[nodiscard]] OriginKind kind() const { return Kind; }
};

void readBytecode(std::string_view &Data, Origin &Obj);
void writeBytecode(std::ostream &OS, const Origin &O);

class OriginPath : public Origin {
std::string Path;

public:
OriginPath() : Origin(OK_Path) {}

[[nodiscard]] std::string &path() { return Path; }
[[nodiscard]] const std::string &path() const { return Path; }
};

void readBytecode(std::string_view &Data, OriginPath &Obj);
void writeBytecode(std::ostream &OS, const OriginPath &O);

} // namespace nixbc
11 changes: 11 additions & 0 deletions libnixbc/include/nixbc/Type.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include <cstdint>

namespace nixbc {

using NixInt = int64_t;
using NixFloat = double;
using PosInt = uint32_t;

} // namespace nixbc
17 changes: 17 additions & 0 deletions libnixbc/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
libnixbc_deps = [ libbc ]
libnixbc_inc = include_directories('include')

libnixbc_lib = library(
'nixbc',
'src/Origin.cpp',
include_directories: libnixbc_inc,
dependencies: libnixbc_deps,
)

libnixbc = declare_dependency(
include_directories: libnixbc_inc,
link_with: libnixbc_lib,
dependencies: libnixbc_deps,
)

install_subdir('include/nixbc', install_dir: 'include')
15 changes: 15 additions & 0 deletions libnixbc/src/Origin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "nixbc/Origin.h"

#include <cassert>

namespace nixbc {

void readBytecode(std::string_view &Data, Origin &Obj) {}

void writeBytecode(std::ostream &OS, const Origin &O) {}

void readBytecode(std::string_view &Data, OriginPath &Obj) {}

void writeBytecode(std::ostream &OS, const OriginPath &O) {}

} // namespace nixbc
17 changes: 17 additions & 0 deletions libnixf/include/nixf/Bytecode/Write.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// \file
/// \brief Serialization of nixf nodes.
///
/// Serialization is the process of converting nix nodes into a byte stream. The
/// target format is "nixbc".

#pragma once

#include "nixf/Basic/Nodes.h"

#include <cstdint>

namespace nixf {

void writeBytecode(std::ostream &OS, const Node &N);

} // namespace nixf
3 changes: 2 additions & 1 deletion libnixf/meson.build
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
libnixf_deps = [ boost ]
libnixf_deps = [ boost, libnixbc ]

libnixf_inc = include_directories('include')

libnixf = library(
'nixf',
'src/Basic/Nodes.cpp',
'src/Basic/Diagnostic.cpp',
'src/Bytecode/Write.cpp',
'src/Parse/Lexer.cpp',
'src/Parse/ParseAttrs.cpp',
'src/Parse/ParseExpr.cpp',
Expand Down
55 changes: 55 additions & 0 deletions libnixf/src/Bytecode/Write.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "Write.h"

#include <bc/Write.h>

#include <nixbc/Nodes.h>

namespace nixf {

using namespace nixbc;

using bc::writeBytecode;

void writeBytecode(std::ostream &OS, const ExprInt &N) {
writeBytecode(OS, NodeHeader{EK_Int, reinterpret_cast<std::uintptr_t>(&N)});
writeBytecode(OS, N.value());
}

void writeBytecode(std::ostream &OS, const ExprBinOp &N) {
using namespace tok;

if (!N.lhs() || !N.rhs()) // Skip invalid nodes
return;

const Expr &LHS = *N.lhs();
const Expr &RHS = *N.rhs();

switch (N.op().op()) {
case tok_op_add:
// (+ a b) -> (ConcatStrings a b)
writeBytecode(
OS, NodeHeader{EK_ConcatStrings, reinterpret_cast<std::uintptr_t>(&N)});
writeBytecode(OS, static_cast<const Node &>(LHS));
writeBytecode(OS, static_cast<const Node &>(RHS));
return;
default:
break;
}
assert(false && "Unhandled binary operator");
__builtin_unreachable();
}

void writeBytecode(std::ostream &OS, const Node &N) {
switch (N.kind()) {
case Node::NK_ExprInt:
writeBytecode(OS, static_cast<const ExprInt &>(N));
break;
case Node::NK_ExprBinOp:
writeBytecode(OS, static_cast<const ExprBinOp &>(N));
break;
default:
break;
}
}

} // namespace nixf
11 changes: 11 additions & 0 deletions libnixf/src/Bytecode/Write.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "nixf/Bytecode/Write.h"

#include <nixbc/Nodes.h>

namespace nixf {

void writeBytecode(std::ostream &OS, const ExprInt &N);

void writeBytecode(std::ostream &OS, const ExprBinOp &N);

} // namespace nixf
Loading

0 comments on commit 5f134ea

Please sign in to comment.