Skip to content
This repository was archived by the owner on Oct 12, 2026. It is now read-only.

Commit b1d4982

Browse files
committed
Add support for variadic arguments and Logger in Builtins
1 parent 0bf0048 commit b1d4982

6 files changed

Lines changed: 73 additions & 59 deletions

File tree

‎examples/shapes.lbd‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,4 @@ volume_of_cylinder: Float -> Float -> Float = \r: Float.
1313
\h: Float. (mul (area_of_circle r) h)
1414

1515
-- Calculate the volume of a cylinder
16-
(print "Volume of cylinder is: ")
17-
(print (volume_of_cylinder 5.0 10.0))
16+
(print "Volume of cylinder is: " (volume_of_cylinder 5.0 10.0) "\n")

‎examples/std.lbd‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ lte: Float -> Float -> Bool = \x: Float. \y: Float.
2828
(if_zero (cmp x y) true (if_zero (cmp (cmp x y) -1) true false))
2929

3030
gte: Float -> Float -> Bool = \x: Float. \y: Float.
31-
(if_zero (cmp x y) true (if_zero (cmp (cmp x y) 1) true false))
31+
(if_zero (cmp x y) true (if_zero (cmp (cmp x y) 1) true false))

‎include/lbd/intp/builtins.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#pragma once
22

33
#include <lbd/intp/interpreter.h>
4+
#include <lbd/options.h>
45

56
namespace intp::interp {
6-
std::vector<NativeFunction> get_builtins();
7+
std::vector<NativeFunction> get_builtins(options::Options options_ = {});
78
}

‎include/lbd/intp/interpreter.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ namespace intp::interp {
5555
using Impl = std::function<Value(
5656
const std::vector<std::shared_ptr<Thunk> > &, const std::shared_ptr<Env> &)>;
5757

58-
std::size_t arity;
58+
int arity;
5959
std::string name;
6060
Impl impl;
6161

‎src/intp/builtins.cpp‎

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
#include <lbd/intp/builtins.h>
22

33
namespace intp::interp {
4-
// TODO: If Arity is -1 that means it can consume all the arguments
5-
// Prints Argument to stdout and returns the same Argument as Value
4+
static options::Options options_v;
5+
6+
// Prints Argument to stdout and returns 0
67
static NativeFunction make_print() {
78
const std::string name = "print";
89
return {
9-
1, name, [](const std::vector<std::shared_ptr<Thunk> > &args, const std::shared_ptr<Env> &) -> Value {
10-
const Value &value = args[0]->force();
11-
std::cout << value.to_string() << std::endl;
12-
return value;
10+
-1, name, [](const std::vector<std::shared_ptr<Thunk> > &args, const std::shared_ptr<Env> &) -> Value {
11+
for (auto &arg: args) {
12+
const Value &value = arg->force();
13+
std::cout << value;
14+
}
15+
return Value{static_cast<double>(0)};
1316
}
1417
};
1518
}
@@ -21,9 +24,8 @@ namespace intp::interp {
2124
const Value &value1 = args[0]->force();
2225
const Value &value2 = args[1]->force();
2326
if (!std::holds_alternative<double>(value1) || !std::holds_alternative<double>(value2)) {
24-
std::cerr << "runtime error: wrong arguments provided to native function " << name << std::endl
25-
<< name << " signature: Float -> Float -> Float" << std::endl;
26-
exit(EXIT_FAILURE);
27+
options_v.logger.error({}, "runtime error: wrong arguments provided to native function ", name,
28+
"\n", name, " signature: Float -> Float -> Float");
2729
}
2830
const double result = std::get<double>(value1) + std::get<double>(value2);
2931
return Value{result};
@@ -38,9 +40,8 @@ namespace intp::interp {
3840
const Value &value1 = args[0]->force();
3941
const Value &value2 = args[1]->force();
4042
if (!std::holds_alternative<double>(value1) || !std::holds_alternative<double>(value2)) {
41-
std::cerr << "runtime error: wrong arguments provided to native function " << name << std::endl
42-
<< name << " signature: Float -> Float -> Float" << std::endl;
43-
exit(EXIT_FAILURE);
43+
options_v.logger.error({}, "runtime error: wrong arguments provided to native function ", name,
44+
"\n", name, " signature: Float -> Float -> Float");
4445
}
4546
const double result = std::get<double>(value1) - std::get<double>(value2);
4647
return Value{result};
@@ -55,9 +56,8 @@ namespace intp::interp {
5556
const Value &value1 = args[0]->force();
5657
const Value &value2 = args[1]->force();
5758
if (!std::holds_alternative<double>(value1) || !std::holds_alternative<double>(value2)) {
58-
std::cerr << "runtime error: wrong arguments provided to native function " << name << std::endl
59-
<< name << " signature: Float -> Float -> Float" << std::endl;
60-
exit(EXIT_FAILURE);
59+
options_v.logger.error({}, "runtime error: wrong arguments provided to native function ", name,
60+
"\n", name, " signature: Float -> Float -> Float");
6161
}
6262
const double result = std::get<double>(value1) * std::get<double>(value2);
6363
return Value{result};
@@ -72,9 +72,8 @@ namespace intp::interp {
7272
const Value &value1 = args[0]->force();
7373
const Value &value2 = args[1]->force();
7474
if (!std::holds_alternative<double>(value1) || !std::holds_alternative<double>(value2)) {
75-
std::cerr << "runtime error: wrong arguments provided to native function " << name << std::endl
76-
<< name << " signature: Float -> Float -> Float" << std::endl;
77-
exit(EXIT_FAILURE);
75+
options_v.logger.error({}, "runtime error: wrong arguments provided to native function ", name,
76+
"\n", name, " signature: Float -> Float -> Float");
7877
}
7978
const double num1 = std::get<double>(value1);
8079
const double num2 = std::get<double>(value2);
@@ -90,10 +89,10 @@ namespace intp::interp {
9089
3, name, [name](const std::vector<std::shared_ptr<Thunk> > &args, const std::shared_ptr<Env> &) -> Value {
9190
const Value &cond_value = args[0]->force();
9291
if (!std::holds_alternative<double>(cond_value)) {
93-
std::cerr << "runtime error: wrong argument type to native function " << name << "\n"
94-
<< name << " signature: Float -> Any -> Any -> Any\n"
95-
<< "runtime error: expected <double> got " << cond_value << std::endl;
96-
exit(EXIT_FAILURE);
92+
options_v.logger.error({}, "runtime error: wrong arguments provided to native function ", name,
93+
"\n", name,
94+
" signature: Float -> Any -> Any -> Any""\n"
95+
"runtime error: expected <double> got ", cond_value);
9796
}
9897
// Lazy branching: only force the chosen clause
9998
if (const double cond = std::get<double>(cond_value); cond == 0.0) {
@@ -108,41 +107,49 @@ namespace intp::interp {
108107
return std::make_shared<List>(List{elements});
109108
}
110109

111-
static Value list_get(const std::shared_ptr<List> &lst, size_t index) {
112-
if (index >= lst->elements.size())
110+
static Value list_get(const std::shared_ptr<List> &list_v, size_t index) {
111+
if (index >= list_v->elements.size())
113112
throw std::out_of_range("list index out of range");
114-
return lst->elements[index];
113+
return list_v->elements[index];
115114
}
116115

117-
static void list_append(std::shared_ptr<List> &lst, Value val) {
118-
lst->elements.push_back(std::move(val));
116+
static void list_append(const std::shared_ptr<List> &list_v, Value value) {
117+
list_v->elements.push_back(std::move(value));
119118
}
120119

121120
static NativeFunction make_list() {
122121
const std::string name = "list";
123-
// TODO: Make this variadic
124122
return {
125-
1, name, [](const std::vector<std::shared_ptr<Thunk> > &args, const std::shared_ptr<Env> &) -> Value {
126-
std::vector<Value> vals;
127-
for (auto &th: args) vals.push_back(th->force());
128-
return make_list_obj(vals);
123+
-1, name, [](const std::vector<std::shared_ptr<Thunk> > &args, const std::shared_ptr<Env> &) -> Value {
124+
std::vector<Value> values;
125+
for (auto &arg: args) {
126+
values.push_back(arg->force());
127+
}
128+
return make_list_obj(values);
129129
}
130130
};
131131
}
132132

133133
static NativeFunction make_list_append() {
134134
const std::string name = "list_append";
135135
return {
136-
2, name, [](const std::vector<std::shared_ptr<Thunk> > &args, const std::shared_ptr<Env> &) -> Value {
137-
// TODO: Add error handling
138-
auto lst = std::get<std::shared_ptr<List> >(args[0]->force());
139-
list_append(lst, args[1]->force());
140-
return lst;
136+
2, name, [name](const std::vector<std::shared_ptr<Thunk> > &args, const std::shared_ptr<Env> &) -> Value {
137+
const Value &arg0 = args[0]->force();
138+
if (!std::holds_alternative<std::shared_ptr<List> >(arg0)) {
139+
options_v.logger.error({}, "runtime error: wrong arguments provided to native function ", name,
140+
"\n", name,
141+
" signature: List -> Any -> List""\n"
142+
"runtime error: expected <List> got ", arg0);
143+
}
144+
auto list_v = std::get<std::shared_ptr<List> >(arg0);
145+
list_append(list_v, args[1]->force());
146+
return list_v;
141147
}
142148
};
143149
}
144150

145-
std::vector<NativeFunction> get_builtins() {
151+
std::vector<NativeFunction> get_builtins(const options::Options options_) {
152+
options_v = options_;
146153
return {
147154
{make_print()},
148155
{make_add()},

‎src/intp/interpreter.cpp‎

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#include <sstream>
66

77
namespace intp::interp {
8-
options::Options options_v;
8+
static options::Options options_v;
99

1010
[[nodiscard]] std::string Closure::to_string() const {
1111
std::ostringstream oss;
@@ -21,7 +21,7 @@ namespace intp::interp {
2121
std::ostringstream oss;
2222
oss << "[";
2323
for (size_t i = 0; i < elements.size(); ++i) {
24-
oss << elements[i].to_string();
24+
oss << elements[i];
2525
if (i + 1 != elements.size()) {
2626
oss << ", ";
2727
}
@@ -233,26 +233,33 @@ namespace intp::interp {
233233
// Native Function case: Consumes its arity-many Argument Thunks
234234
else if (std::holds_alternative<std::shared_ptr<NativeFunction> >(current_fn)) {
235235
const auto &[arity, name, impl] = *std::get<std::shared_ptr<NativeFunction> >(current_fn);
236-
if (work_args.size() - idx < arity) {
237-
options_v.logger.error(call_loc, "runtime error: native function ", name, " expects ", arity,
238-
" argument(s), found ", work_args.size() - idx);
239-
std::exit(EXIT_FAILURE);
240-
}
241-
std::vector<std::shared_ptr<Thunk> > slice;
242-
slice.reserve(arity);
243-
for (size_t i = 0; i < arity; ++i) {
244-
slice.push_back(work_args[idx + i]);
236+
if (arity != -1) {
237+
if (work_args.size() - idx < arity) {
238+
options_v.logger.error(call_loc, "runtime error: native function ", name, " expects ", arity,
239+
" argument(s), found ", work_args.size() - idx);
240+
}
241+
std::vector<std::shared_ptr<Thunk> > slice;
242+
slice.reserve(arity);
243+
for (size_t i = 0; i < arity; ++i) {
244+
slice.push_back(work_args[idx + i]);
245+
}
246+
resultant_value = impl(slice, call_site_env);
247+
idx += arity;
248+
} else {
249+
std::vector<std::shared_ptr<Thunk> > slice;
250+
slice.reserve(args.size() - idx);
251+
for (size_t i = 0; i < args.size() - idx; ++i) {
252+
slice.push_back(work_args[idx + i]);
253+
}
254+
resultant_value = impl(slice, call_site_env);
255+
idx += args.size() - idx;
245256
}
246-
resultant_value = impl(slice, call_site_env);
247-
idx += arity;
248257
} else {
249258
// Top frame is not a Function (Closure, NativeFunction) Value but there are still Arguments left
250259
options_v.logger.error(call_loc, "runtime error: trying to apply non-function value ", frames.back());
251-
std::exit(EXIT_FAILURE);
252260
}
253261
if (!resultant_value) {
254262
options_v.logger.error(call_loc, "internal error: application produced no result");
255-
std::exit(EXIT_FAILURE);
256263
}
257264
if (std::holds_alternative<Closure>(*resultant_value) ||
258265
std::holds_alternative<std::shared_ptr<NativeFunction> >(*resultant_value)) {
@@ -324,7 +331,7 @@ namespace intp::interp {
324331
}
325332

326333
void install_builtins(const std::shared_ptr<Env> &env) {
327-
for (auto &native_fn: get_builtins()) {
334+
for (auto &native_fn: get_builtins(options_v)) {
328335
const auto thunk = std::make_shared<Thunk>();
329336
thunk->cached = Value{std::make_shared<NativeFunction>(native_fn)};
330337
env->bind(native_fn.name, thunk);

0 commit comments

Comments
 (0)