Skip to content

Commit 2cdb761

Browse files
committed
Merge remote-tracking branch 'origin/main' into gh-pages
2 parents d03dd43 + 3f8a743 commit 2cdb761

72 files changed

Lines changed: 1819 additions & 632 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/benchmark.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
sum=0
3333
for i in $(seq $NTIMES); do
3434
before=$(gettimems)
35-
./cbcvm bench/bf.rbcvm bench/bench.b
35+
./cbcvm bench/bf.cb bench/bench.b
3636
after=$(gettimems)
3737
elapsed=$((after - before))
3838
sum=$((sum + elapsed))
@@ -43,7 +43,7 @@ jobs:
4343
sum=0
4444
for i in $(seq $NTIMES); do
4545
before=$(gettimems)
46-
./cbcvm bench/nbody.rbcvm 500000
46+
./cbcvm bench/nbody.cb 500000
4747
after=$(gettimems)
4848
elapsed=$((after - before))
4949
sum=$((sum + elapsed))
@@ -54,7 +54,7 @@ jobs:
5454
sum=0
5555
for i in $(seq $NTIMES); do
5656
before=$(gettimems)
57-
./cbcvm bench/spectral_norm.rbcvm 1000
57+
./cbcvm bench/spectral_norm.cb 1000
5858
after=$(gettimems)
5959
elapsed=$((after - before))
6060
sum=$((sum + elapsed))
@@ -65,7 +65,7 @@ jobs:
6565
sum=0
6666
for i in $(seq NTIMES); do
6767
before=$(gettimems)
68-
./cbcvm bench/binary_trees.rbcvm 21
68+
./cbcvm bench/binary_trees.cb 21
6969
after=$(gettimems)
7070
elapsed=$((after - before))
7171
sum=$((sum + elapsed))

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
WARNINGS=-Wnull-dereference -Wall -Winline -Wextra -Wno-unused-parameter
22
CFLAGS+=-g -std=gnu11 $(WARNINGS) -I$(CURDIR) -I$(CURDIR)/vendor
3-
LDFLAGS+=-lm -lreadline -Lvendor/utf8proc vendor/utf8proc/libutf8proc.a
3+
LDLIBS+=-lm -lreadline vendor/utf8proc/libutf8proc.a
44
SANITIZERS+=address,undefined
55

66
ifeq ($(TARGET),release)
@@ -25,7 +25,7 @@ OBJ := $(patsubst %.c,%.o,$(SRC))
2525
DEP := $(patsubst %.o,%.d,$(OBJ))
2626

2727
cbcvm: $(OBJ) vendor/utf8proc/libutf8proc.a
28-
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
28+
$(CC) $(CFLAGS) -o $@ $(OBJ) $(LDFLAGS) $(LDLIBS)
2929

3030
-include $(DEP)
3131

@@ -38,7 +38,7 @@ vendor/utf8proc/libutf8proc.a:
3838
# Generate a release binary using profile-guided optimization
3939
profile-opt:
4040
CFLAGS='-fprofile-generate' $(MAKE) clean cbcvm TARGET=release
41-
./cbcvm bf.rbcvm bench.b
41+
./cbcvm bf.cb bench.b
4242
$(MAKE) clean
4343
CFLAGS='-fprofile-use -fprofile-correction' $(MAKE) TARGET=release
4444
find . -name '*.gcda' -delete

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ import test;
299299

300300
Upon encountering this statement, the compiler will search for a module with
301301
that name. If a built-in module exists with that name, it's imported. If not,
302-
the compiler will search for a file called (in this case) `test.rbcvm` in each
302+
the compiler will search for a file called (in this case) `test.cb` in each
303303
of the paths defined in the `CBCVM_PATH` environment variable. This variable
304304
should be a colon-separated list of directories. Once it finds a module with
305305
that name, any imports of that name will result in the same module being
@@ -360,7 +360,7 @@ Here are some idioms that have appeared in the standard library:
360360
This language has no generators, nor any built-in iteration protocol. The way
361361
this is done in the standard library (see the [iter] module) is using closures.
362362

363-
[iter]: https://github.com/p7g/c-bytecode-vm/blob/master/lib/iter.rbcvm
363+
[iter]: https://github.com/p7g/c-bytecode-vm/blob/main/lib/iter.cb
364364

365365
This is easiest to illustrate with an example:
366366
```js

agent.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,12 @@ int cb_agent_init(void)
9292
for (i = 1; i < MAX_IMPORT_PATHS; i += 1)
9393
agent.import_paths[i] = NULL;
9494

95+
char *lasts;
9596
agent.cbcvm_path = getenv("CBCVM_PATH");
9697
if (agent.cbcvm_path) {
9798
agent.cbcvm_path = strdup(agent.cbcvm_path);
98-
for (i = 1, path = strtok(agent.cbcvm_path, ":"); path;
99-
i += 1, path = strtok(NULL, ":")) {
99+
for (i = 1, path = strtok_r(agent.cbcvm_path, ":", &lasts); path;
100+
i += 1, path = strtok_r(NULL, ":", &lasts)) {
100101
if (i >= MAX_IMPORT_PATHS) {
101102
fprintf(stderr, "Too many paths in CBCVM_PATH\n");
102103
goto error;
@@ -263,7 +264,7 @@ CB_INLINE size_t cb_agent_modspec_count(void)
263264
}
264265

265266
/* Given a name like "hashmap", find a matching file relative to one of the
266-
paths in CBCVM_PATH with a .rbcvm extension. If found, it will be opened and
267+
paths in CBCVM_PATH with a .cb extension. If found, it will be opened and
267268
a FILE handle returned. Otherwise NULL will be returned, and an error
268269
message will be printed.
269270
@@ -305,7 +306,7 @@ FILE *cb_agent_resolve_import(cb_str import_name, const char *pwd,
305306
cb_strlen(import_name)));
306307
CHECK_LEN;
307308
j += cb_strlen(import_name);
308-
strncpy(path + j, ".rbcvm", MAX_IMPORT_PATH_LEN - j);
309+
strncpy(path + j, ".cb", MAX_IMPORT_PATH_LEN - j);
309310
CHECK_LEN;
310311

311312
f = fopen(path, "rb");

bench/bf.rbcvm renamed to bench/bf.cb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ function parse(it) {
3838
let ops = arraylist::new();
3939
let c;
4040

41-
while ((c = it()) != iter::STOP) {
41+
while ((c = iter::next(it)) != iter::STOP) {
4242
if (c == '+') {
4343
arraylist::push(ops, Op{type="inc", value=1});
4444
} else if (c == '-') {
@@ -81,8 +81,8 @@ function run(tape, ops) {
8181

8282
let args = argv();
8383
if (array::length(args) != 1) {
84-
println("Usage: ./cbcvm bf3.rbcvm <program>");
84+
println("Usage: ./cbcvm bf.cb <program>");
8585
} else {
86-
let it = array::iter(string::chars(fs::read_file(args[0])));
86+
let it = iter::iter(fs::read_file(args[0]));
8787
run(tape_new(), parse(it));
8888
}
File renamed without changes.

compiler.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,8 +2041,11 @@ static ssize_t compile_struct_decl(struct cstate *state, size_t *name_out,
20412041
if (first_field) {
20422042
first_field = 0;
20432043
} else {
2044-
if (!in_methods)
2044+
if (!in_methods) {
20452045
EXPECT(TOK_COMMA);
2046+
} else if (MATCH_P(TOK_COMMA)) {
2047+
ERROR_AT(NEXT(), "Methods should not be separated by commas");
2048+
}
20462049
/* support trailing comma */
20472050
if (MATCH_P(TOK_RIGHT_BRACE))
20482051
break;
@@ -2056,7 +2059,8 @@ static ssize_t compile_struct_decl(struct cstate *state, size_t *name_out,
20562059
ERROR_AT(NEXT(), "Too many methods");
20572060
return -1;
20582061
}
2059-
X(compile_function(state, &fields[num_fields + num_methods++], 1));
2062+
if (compile_function(state, &fields[num_fields + num_methods++], 1))
2063+
return -1;
20602064
} else if (in_methods) {
20612065
ERROR_AT(NEXT(), "All fields must come before methods");
20622066
return -1;
@@ -2092,8 +2096,8 @@ static ssize_t compile_struct_decl(struct cstate *state, size_t *name_out,
20922096
APPEND1(OP_LOAD_CONST, const_id);
20932097

20942098
if (in_methods) {
2095-
for (unsigned i = num_fields + num_methods - 1;
2096-
i >= methods_start; i--)
2099+
for (int i = num_fields + num_methods - 1;
2100+
i >= (ssize_t) methods_start; i--)
20972101
APPEND2(OP_SET_METHOD, i - methods_start, fields[i]);
20982102
}
20992103

docs/stdlib.md

Lines changed: 114 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
Index:
44
- [docs](#docs-module)
5+
- [trait](#trait-module)
56
- [array](#array-module)
67
- [list](#list-module)
78
- [math](#math-module)
@@ -53,6 +54,89 @@ The interface for a documentation generator.
5354

5455
Create an object to document members of a module.
5556

57+
## trait module
58+
59+
60+
A trait is a reusable set of methods that can be used to extend the behavior of
61+
a type. It's an interface that defines a contract that must be implemented by
62+
any type that wishes to support the trait. Any objects that implement the trait
63+
can be converted to a _trait object_, which can be used to call the methods
64+
defined by the trait.
65+
66+
For example, you can define a `Printable` trait with a method `print()`:
67+
```c++
68+
let Printable = trait::new("Printable", [trait::method("print")]);
69+
70+
trait::impl(Printable, MyType, struct {
71+
function print(self) {
72+
println("MyType ", self.value);
73+
}
74+
});
75+
76+
# Both equivalent:
77+
Printable.print(MyType { value = 42 });
78+
trait::cast(Printable, MyType { value = 42 }).print();
79+
```
80+
81+
82+
### function `implements(obj, trait)`
83+
84+
Check if an object implements a trait.
85+
86+
If `obj` is a trait object, `implements` will return true if its trait is
87+
`trait`. Otherwise return true if `obj` implements the trait and could be cast
88+
to a trait object for `trait`.
89+
90+
### function `downcast(traitobject)`
91+
92+
Retrieve the underlying object from a trait object.
93+
94+
### function `impl(trait, type, implementation)`
95+
96+
Implement a trait for some type.
97+
98+
The `implementation` should be a struct containing methods for each method
99+
defined in the trait. For example:
100+
101+
```c++
102+
trait::impl(ToString, MyType, struct {
103+
function to_string(self) {
104+
# ...
105+
}
106+
});
107+
```
108+
109+
### function `primitive(typename)`
110+
111+
Used to specify a primitive type like `"string"` as the implementor of a trait. Example:
112+
113+
```c++
114+
trait::impl(ToString, trait::primitive("string"), struct {
115+
function to_string(self) {
116+
return self;
117+
}
118+
});
119+
```
120+
121+
122+
### function `cast(trait, obj)`
123+
124+
Create a trait object for the given trait and object.
125+
126+
`obj` must be an object that implements the trait. Any trait methods can be
127+
called directly on the trait object.
128+
129+
### function `new(name, methods)`
130+
131+
Create a new trait with the given name and methods.
132+
133+
Any implementors must define all methods, though the signature of the methods is
134+
not checked.
135+
136+
### function `method(name)`
137+
138+
Create a trait method declaration for use with `trait::new()`
139+
56140
## array module
57141
58142
Functions for working with arrays.
@@ -112,10 +196,6 @@ Find the index of the element for which `predicate` returns true. If there is no
112196
113197
A collector for converting an iterator into an array.
114198
115-
### function `iter(array)`
116-
117-
Create an iterator from array `array`.
118-
119199
### function `length(array)`
120200
121201
Get the length of array `array`.
@@ -184,10 +264,6 @@ Insert `value` at the front of `list`
184264
185265
Get the length of the list.
186266
187-
### function `iter(list)`
188-
189-
Create an iterator over `list`.
190-
191267
### function `new()`
192268
193269
Create a new, empty linked list.
@@ -393,9 +469,37 @@ Create an iterator that counts from 0 to `to`.
393469
394470
Create an iterator that counts up from `n` indefinitely.
395471
396-
### struct `collector`
472+
### method `finalize()`
473+
474+
Finalizes the collection by returning the reduced result.
475+
476+
### method `reduce()`
477+
478+
Reduces the iterator into the collection by adding an item.
479+
480+
### method `init()`
481+
482+
Initializes the collection for reduction.
483+
484+
### trait `Collector`
485+
486+
A trait for converting an iterator into an arbitrary collection.
487+
488+
### method `next()`
489+
490+
Returns the next value in the sequence, or STOP if there are no more values.
491+
492+
### trait `Iterator`
493+
494+
A trait for objects that can produce a sequence of values.
397495
398-
An struct defining the required functions to convert an iterator into an arbitrary collection.
496+
### method `iter()`
497+
498+
Returns an iterator for the object.
499+
500+
### trait `Iterable`
501+
502+
A trait for objects that can be iterated over.
399503
400504
### object `STOP`
401505
@@ -476,10 +580,6 @@ Create an empty arraylist with default initial capacity.
476580
477581
Create an empty arraylist with the given initial capacity.
478582
479-
### function `iter(list)`
480-
481-
Create an iterator over arraylist `list`.
482-
483583
### function `from_array(len, array)`
484584
485585
Create a new arraylist from `array`. The `len` argument should be the length
@@ -518,10 +618,6 @@ Set the value of `key` in `list` to `value`.
518618
A collector for converting an iterator of
519619
entries into an assoclist.
520620
521-
### function `iter(list)`
522-
523-
Create an iterator over the entries of `list`.
524-
525621
### function `length`
526622
527623
Check the number of items in the list.
@@ -534,10 +630,6 @@ Create an empty assoclist.
534630
535631
A compact byte array type.
536632
537-
### function `iter(bytes)`
538-
539-
Create an iterator over `bytes`.
540-
541633
### object `collector`
542634
543635
A collector for converting an iterator into byte array.
@@ -711,10 +803,6 @@ Parse `str` as an integer of base `base`. Currently only works for base 10.
711803
A collector to convert an iterator of characters
712804
or strings into a string.
713805
714-
### function `iter(str)`
715-
716-
Create an iterator over the characters in `str`.
717-
718806
### function `from_bytes(bytes)`
719807
720808
Convert a byte array to a string.
@@ -884,10 +972,6 @@ Get an iterator over the keys in `map`.
884972
885973
Return the number of values in `map`.
886974
887-
### function `iter(map)`
888-
889-
Get an iterator over the key-value pairs in `map`.
890-
891975
### function `entries(map)`
892976
893977
Get an iterator over the key-value pairs in `map`.

0 commit comments

Comments
 (0)