Skip to content

Commit 915a5d7

Browse files
committed
ffi example works now
1 parent 9978701 commit 915a5d7

10 files changed

Lines changed: 194 additions & 94 deletions

File tree

lib/libtest.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ extern "C" {
1818

1919
void print() { printf("It's working!\n"); }
2020

21+
int mul(int a, int b){
22+
int r = a * b;
23+
printf("Test mul (%d, %d)\n", a, b);
24+
return r;
25+
}
26+
2127
void test_v() {
2228
printf("Test: void()\n");
2329
}

mfiles/extern.m

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
# expect_result=15
22

3-
# TODO: Implement parsing for extern, register extern functions to use in call later
4-
let mul = extern libprint::mul(a: Int, b: Int): Int;
3+
let mul = extern test::mul(a: Int, b: Int): Int;
54

6-
# TODO: Implement calls to extern functions
75
let i = 5;
86
let result = mul(i, 3);
97
ret result;

src/ast/DataType.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ DataType::DataType(const std::string& str) // TODO, maybe remove
1414
DataType::DataType(const std::vector<DataType>& params, DataType ret)
1515
: impl(Function{
1616
std::make_shared<const std::vector<DataType>>(params),
17-
std::make_shared<const DataType>(ret)}) {}
17+
std::make_shared<const DataType>(ret), false /*isExtern*/}) {}
18+
19+
DataType::DataType(const std::vector<DataType>& params, DataType ret, bool isExtern)
20+
: impl(Function{
21+
std::make_shared<const std::vector<DataType>>(params),
22+
std::make_shared<const DataType>(ret),
23+
isExtern}) {}
1824

1925
DataType::DataType(DataType::Struct structType)
2026
: impl(structType) {}
@@ -39,7 +45,8 @@ bool DataType::operator==(const DataType& other) const {
3945
const auto& thisFunc = std::get<Function>(impl);
4046
const auto& otherFunc = std::get<Function>(other.impl);
4147
return *thisFunc.ret == *otherFunc.ret &&
42-
*thisFunc.params == *otherFunc.params;
48+
*thisFunc.params == *otherFunc.params &&
49+
thisFunc.isExtern == otherFunc.isExtern;
4350
} else if (std::holds_alternative<Struct>(impl)) {
4451
return std::get<Struct>(impl).name == std::get<Struct>(other.impl).name;
4552
}
@@ -114,15 +121,18 @@ std::string DataType::toString() const {
114121
const auto& params = func.params;
115122
const auto& ret = func.ret;
116123
std::stringstream stream;
117-
if (params->size() > 1u) stream << "[";
118-
if (params->empty()) stream << "[]";
124+
if(func.isExtern) {
125+
stream << "ext_";
126+
}
127+
stream << "[";
128+
if (params->empty()) stream << "]";
119129
for (auto it = params->begin(); it != params->end(); ++it) {
120130
stream << it->toString();
121131
if (std::next(it) != params->end()) {
122132
stream << ", ";
123133
}
124134
}
125-
if (params->size() > 1u) stream << "]";
135+
if (params->size() >= 1u) stream << "]";
126136
stream << " -> " << ret->toString();
127137
return stream.str();
128138
} else if (std::holds_alternative<Struct>(impl)) {

src/ast/DataType.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class DataType {
4343
// Types[] -> Type
4444
std::shared_ptr<const std::vector<DataType>> params;
4545
std::shared_ptr<const DataType> ret;
46+
bool isExtern;
4647
};
4748

4849
std::variant<Simple, Function, Struct> impl;
@@ -54,6 +55,7 @@ class DataType {
5455

5556
// Function type constructor
5657
DataType(const std::vector<DataType>& params, DataType ret);
58+
DataType(const std::vector<DataType>& params, DataType ret, bool isExtern);
5759

5860
// Struct
5961
DataType(Struct structType);

src/emitter/ByteCodeEmitter.cpp

Lines changed: 99 additions & 73 deletions
Large diffs are not rendered by default.

src/emitter/ByteCodeEmitter.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ class ByteCodeEmitter {
1919

2020
private:
2121
std::map<std::string, std::shared_ptr<AST::Function>> functions;
22-
std::vector<executor::word_t> data;
23-
std::vector<executor::Instruction> code;
22+
executor::Program program;
2423

2524
struct Backpatch {
2625
size_t instruction_idx;
@@ -38,6 +37,10 @@ class ByteCodeEmitter {
3837
executor::Program getProgram();
3938

4039
protected:
40+
std::vector<executor::Instruction>& code() {
41+
return program.code;
42+
}
43+
4144
void process(const std::shared_ptr<AST::Node>& node, bool hasConsumer);
4245
void loadIdentifier(const std::shared_ptr<AST::Identifier>& identifier);
4346
void storeLocalInto(const std::shared_ptr<AST::Node>& node);

src/executer/ByteCode.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ std::string instructionsToString(const std::vector<Instruction>& instructions, b
4242
{ Op::GTE, {"GTE", {}} },
4343
{ Op::NEQ, {"NEQ", {}} },
4444
{ Op::DUB, {"DUB", {"LOOKBACK"}} },
45-
{ Op::REG_FFI, {"REG_FFI", {}} },
45+
{ Op::REG_FFI, {"REG_FFI", { "LIB_DATA_IDX", "NAME_DATA_IDX" }} },
4646
{ Op::PUSH_FFI_WORD, {"PUSH_FFI_WORD", {}} },
4747
{ Op::PUSH_FFI_DWORD, {"PUSH_FFI_DWORD", {}} },
4848
{ Op::PUSH_FFI_QWORD, {"PUSH_FFI_QWORD", {}} },
@@ -276,9 +276,10 @@ ProgramState ByteCodeVM::run(size_t maxInstructions) {
276276
}
277277
case Op::REG_FFI: {
278278
// Register FFI function
279-
// TODO: How do we get strings here?
280-
// TODO: Need to somehow embed strings into the bytecode
281-
ffiFunctions.add("library", "function");
279+
auto lib = program.data.getString(inst.arg1); // Library name
280+
auto name = program.data.getString(inst.arg2); // Function name
281+
auto id = ffiFunctions.add(lib, name);
282+
stack.push(id);
282283
break;
283284
}
284285
case Op::PUSH_FFI_WORD:

src/executer/ByteCode.h

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
namespace executor {
1414

1515
using word_t = unsigned long;
16+
static_assert(sizeof(word_t) == 8);
1617

1718
enum class Op {
1819
NOP,
@@ -68,8 +69,37 @@ struct OpCodeMetadata {
6869

6970
std::string instructionsToString(const std::vector<Instruction>& instructions, bool named_args = false);
7071

72+
class Data {
73+
// TODO: Bring into cpp
74+
private:
75+
using byte_t = unsigned char;
76+
static_assert(sizeof(byte_t) == 1);
77+
std::vector<byte_t> data;
78+
79+
public:
80+
Data(): data() {}
81+
82+
char* getString(size_t idx){
83+
if (idx >= data.size()) {
84+
throwConstraintViolated("Data: Index out of bounds");
85+
}
86+
return reinterpret_cast<char*>(&data[idx]);
87+
}
88+
89+
size_t addString(const std::string& str) {
90+
size_t startIdx = data.size();
91+
data.resize(startIdx + str.size() + 1); // +1 for null terminator
92+
93+
for (size_t i = 0; i < str.size(); ++i) {
94+
data[startIdx + i] = static_cast<byte_t>(str[i]);
95+
}
96+
data[startIdx + str.size()] = 0; // Null terminator
97+
return startIdx;
98+
}
99+
};
100+
71101
struct Program {
72-
std::vector<word_t> data; // TODO: Unused
102+
Data data;
73103
std::vector<Instruction> code;
74104
};
75105

src/mains/Tests.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
#include <string>
88
#include <optional>
99

10+
#define RUN_TEST_LABEL() \
11+
std::cout << "[ START ] " << __FUNCTION__ << std::endl;
12+
13+
#define END_TEST_LABEL() \
14+
std::cout << "[ OK ] " << __FUNCTION__ << std::endl;
15+
1016
#define EXPECT_EQ(expected, actual) \
1117
if ((expected) != (actual)) { \
1218
std::cerr << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__ << " Expected: " << (expected) << ", but got: " << (actual) << std::endl; \
@@ -79,7 +85,7 @@ bool compareResults(const std::string& expected, const std::string& actual) {
7985
}
8086

8187
void testFile(std::string path){
82-
std::cout << "Testing file: " << path << std::endl;
88+
std::cout << "[ START ] " << path << std::endl;
8389

8490
auto metadata = readMetadata(path);
8591
std::optional<std::string> expectResult;
@@ -124,11 +130,11 @@ void testFile(std::string path){
124130
EXPECT_TRUE(rs == core::Mlang::Result::Signal::Success);
125131
}
126132

127-
std::cout << "[ OK ] " << path << std::endl;
133+
std::cout << "[ OK ] " << path << std::endl;
128134
}
129135

130136
void testLibrary(){
131-
std::cout << "Testing ffi..." << std::endl;
137+
RUN_TEST_LABEL();
132138

133139
ffi::ExternalFunctions externalFunctions;
134140

@@ -229,7 +235,24 @@ void testLibrary(){
229235
EXPECT_EQ(expected, result);
230236
}
231237

232-
std::cout << "[ OK ] ffi test passed." << std::endl;
238+
END_TEST_LABEL();
239+
}
240+
241+
void testExecutorData(){
242+
RUN_TEST_LABEL();
243+
executor::Data data;
244+
auto idx = data.addString("Hello");
245+
EXPECT_EQ("Hello", std::string(data.getString(idx)));
246+
247+
idx = data.addString("World");
248+
EXPECT_EQ("World", std::string(data.getString(idx)));
249+
250+
idx = data.addString("Hello World");
251+
EXPECT_EQ("Hello World", std::string(data.getString(idx)));
252+
253+
// Check that the strings are null-terminated
254+
EXPECT_EQ('\0', data.getString(idx)[11]);
255+
END_TEST_LABEL();
233256
}
234257

235258
void suiteTestfiles(){
@@ -262,12 +285,13 @@ void suiteTestfiles(){
262285
// testFile("mfiles/blob.m");
263286

264287
// TODO: Extern functions
265-
// testFile("mfiles/extern.m");
288+
testFile("mfiles/extern.m");
266289
}
267290

268291
int main() {
269292
suiteTestfiles();
270293
testLibrary();
294+
testExecutorData();
271295
// Structs:
272296
// member functions for structs
273297

src/transformer/ApplyTypeAnnotations.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ std::shared_ptr<AST::Node> ApplyTypeAnnotations::process(std::shared_ptr<AST::No
7171
}
7272

7373
if(returnType) {
74-
externFn->setDataType(DataType(params, *returnType), [this](auto& s) { this->addMessage(s); });
74+
externFn->setDataType(DataType(params, *returnType, true /* extern */), [this](auto& s) { this->addMessage(s); });
7575
}
7676
} else {
7777
followChildren(node);

0 commit comments

Comments
 (0)