mattwparas / steel Goto Github PK
View Code? Open in Web Editor NEWAn embedded scheme interpreter in Rust
License: Apache License 2.0
An embedded scheme interpreter in Rust
License: Apache License 2.0
Using rust:slim
as base img
At the following Dockerfile steps:
RUN mkdir -p /lib/steel && \
export STEEL_HOME="/lib/steel"
RUN cargo build
RUN target/debug/steel cogs/install.scm
I get this below err:
error[E11]: Generic
┌─ cogs/install.scm:11:1
│
11 │
│ Error: Generic: environment variable not found
Error: SteelErr { repr: Repr { kind: Generic, message: "Error: Generic: environment v
ariable not found", span: Some(1085..1092), stack_trace: Some(DehydratedStackTrace {
stack_trace: [] }) } }
The command '/bin/sh -c ls target/** && target/debug/steel cogs/install.scm' returned
a non-zero code: 1
Did i miss setting any ENV ?
The playground is pretty out of date, and does not currently reflect the existing build.
I attempted to understand the inner workings of run-tests.scm
here.
Today, we could consider placing a default copy of run-tests.scm
in the project directory, allowing steel test
to run that file as one possible option.
I believe the purpose of the steel test
command is to simplify test execution for users, abstracting away the details of the testing system implementation. This implies that we would need to reimplement run-test.scm
within the command line. However, this approach has a tradeoff – it makes 'steel' responsible for the testing strategy. I'm not entirely sure how other programming languages handle different testing frameworks (like JUnit in Java, Mocha and Jest in JavaScript, or HSpec, HUnit, QuickCheck... in Haskell). They either have standalone command-line interfaces or provide a test driver of some kind. I think Golang go test
and Rust cargo test
are very opinionated here. But I admit I'm not well-informed on this topic.
as an initial proof of concept I implemented it by replicating the behavior of run-tests.scm
as follows:
fn test_files(dir: &PathBuf, paths: &mut Vec<PathBuf>) -> Result<(), Box<dyn Error>> {
if dir.is_dir() {
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
test_files(&path, paths)?;
} else {
if path.is_file()
&& path
.file_name()
.map(|name| name.to_str().map_or(false, |n| n.ends_with(".scm")))
.unwrap_or(false)
{
paths.push(path);
}
}
}
}
Ok(())
}
fn run_folder_tests(project_root: &PathBuf) -> Result<(), Box<dyn Error>> {
let mut vm = Engine::new();
vm.register_value("std::env::args", steel::SteelVal::ListV(vec![].into()));
vm.run("(set-test-mode!)")?;
let mut files = Vec::new();
if project_root.is_file() {
files.push(project_root.clone());
} else {
test_files(project_root, &mut files)?;
}
for file in &files {
let contents = fs::read_to_string(&file)?;
if let Err(e) = vm.compile_and_run_raw_program_with_path(&contents, file.clone()) {
e.emit_result(file.to_str().unwrap(), &contents);
return Err(Box::new(e));
}
}
let get_test_stats = r#"(require "steel/tests/unit-test.scm") (get-test-stats)"#;
if let Err(e) = vm.run(get_test_stats) {
e.emit_result(project_root.to_str().unwrap(), &get_test_stats);
return Err(Box::new(e));
}
Ok(())
}
I had to reimplement the 'walk-dir' function and make some adjustments to the execution path, but it appears to be working well.
I'm super open to your feedback and thoughts. Please let me know if there are alternative approaches or if the current implementation is satisfactory, and I can proceed with opening a pull request.
We could also improve by ignoring hidden files and patterns from .gitignore, but that's not our top priority for now.
See ports in here https://small.r7rs.org/attachment/r7rs.pdf
Not all of these need to be implemented as native functions, but there are only a handful of port related functions currently implemented.
steel-interpreter REPL
Redefinition of any Steel function, or standard functions such as Ok->value
replaces the function definition.
Redefining +
or *
does nothing.
Either:
Currently the process is as follows:
Ideally the scheme would allow extension of syntax by the implementation of a macro system. This would add a step in between parsing and evaluating, known as the "expansion" phase.
This phase could also be added inside the evaluation step. Macros could be identified and expanded just in time at evaluation time.
The expansion phase would expand macros into primitive operations. For example:
(and a b c)
Would translate to:
(if a
(if b
c
#f)
#f)
Other built in macros that should exist:
unless
and
or
cond
Thanks for your spec. This is a good start, and I like where you’re going with it. I have just a few thoughts/suggestions/questions:
I’d like to see a bit of API sketch in the spec, or maybe you could point me to what you have. You probably needs not just marshaling traits, but a type for the interpreter itself and types for handling Scheme values on the Rust side.
What is “Partial Tail-call Optimization”? Why not full TCO?
In addition to wrapping Rust functions as Scheme functions, you probably need to be able to wrap other Rust values as well. It should possible to make it easy to turn, say, a mutex into a Scheme value, along with a new predicate that recognizes it.
Have you thought about reentrancy? For example, if you call into Scheme and the from Scheme you call a Rust function, can that Rust function then call back into Scheme (and so on)? What happens when you have an error on the Scheme side? (Maybe you want a method for entering Scheme that returns a Result<SchemeValue, SchemeError>
back to Rust.) The harder question is what happens if Rust code called from Scheme code panics. Does the Scheme context get to see that?
Instead of having records defined in Scheme, it might make more sense to make it easy to embed Rust structs. Maybe the programmer could write,
#[derive(Scheme)]
struct Wib {
xam: u32,
sqo: String,
}
and that would not only derive the trait for turning a Wib
into a Scheme value and back, but also Scheme functions: a constructor wib
, a predicate wib?
, getters wib-xam
and wib-sqo
, and setters set-wib-xam!
and set-wib-sqo!
.
Your public API may need a notion of a Scheme environment that can be manipulated from Rust.
Have you thought about whether it’s possible to include borrowed values in Scheme values? Can you check lifetimes dynamically? (Yes, sort of.)
Is escaping backquotes done this way, or is it still unimplemented?
54 │ [else '(you can\'t go that way.)])))
│ ^ Parse: Unexpected character: '\\'
Right now, threads are created by creating a new runtime instance on another thread, where the entire runtime environment is copied and moved over, which is error prone since some values cannot be moved.
Error reporting is also poor on threads - they can error on creation and during runtime, and it will be difficult to know.
It also isn't particularly documented - so this is at least somewhere where progress on it can be documented.
found a panic in the interpreter while playing around, and minimized it to this sequence:
(define (x) (- x 2)) ; define a weird function
(x) ; function is called (TypeMismatch reported)
(define (x) (- x 2)) ; panic when redefining the function
run with ./target/release/steel < crash.scm
thread 'main' panicked at 'range end index 9 out of range for slice of length 5', crates/steel-core/src/steel_vm/vm.rs:2349:17
stack backtrace:
0: rust_begin_unwind
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:578:5
1: core::panicking::panic_fmt
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/panicking.rs:67:14
2: core::slice::index::slice_end_index_len_fail_rt
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/slice/index.rs:78:5
3: core::slice::index::slice_end_index_len_fail
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/slice/index.rs:70:9
4: steel::steel_vm::vm::VmCore::handle_pure_function
5: steel::steel_vm::vm::VmCore::vm
at ./crates/steel-core/src/steel_vm/vm.rs:1993:22
6: steel::steel_vm::vm::SteelThread::execute
at ./crates/steel-core/src/steel_vm/vm.rs:457:26
7: steel::steel_vm::vm::SteelThread::run_executable::{{closure}}
at ./crates/steel-core/src/steel_vm/vm.rs:361:22
8: core::iter::adapters::map::map_try_fold::{{closure}}
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/iter/adapters/map.rs:91:28
9: core::iter::traits::iterator::Iterator::try_fold
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/iter/traits/iterator.rs:2304:21
10: <core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::try_fold
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/iter/adapters/map.rs:117:9
11: <core::iter::adapters::GenericShunt<I,R> as core::iter::traits::iterator::Iterator>::try_fold
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/iter/adapters/mod.rs:195:9
12: core::iter::traits::iterator::Iterator::try_for_each
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/iter/traits/iterator.rs:2366:9
13: <core::iter::adapters::GenericShunt<I,R> as core::iter::traits::iterator::Iterator>::next
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/iter/adapters/mod.rs:178:14
14: <alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/alloc/src/vec/spec_from_iter_nested.rs:26:32
15: <alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/alloc/src/vec/spec_from_iter.rs:33:9
16: <alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/alloc/src/vec/mod.rs:2712:9
17: core::iter::traits::iterator::Iterator::collect
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/iter/traits/iterator.rs:1896:9
18: <core::result::Result<V,E> as core::iter::traits::collect::FromIterator<core::result::Result<A,E>>>::from_iter::{{closure}}
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/result.rs:1969:51
19: core::iter::adapters::try_process
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/iter/adapters/mod.rs:164:17
20: <core::result::Result<V,E> as core::iter::traits::collect::FromIterator<core::result::Result<A,E>>>::from_iter
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/result.rs:1969:9
21: core::iter::traits::iterator::Iterator::collect
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/iter/traits/iterator.rs:1896:9
22: steel::steel_vm::vm::SteelThread::run_executable
at ./crates/steel-core/src/steel_vm/vm.rs:362:14
23: steel::steel_vm::engine::Engine::run_raw_program
at ./crates/steel-core/src/steel_vm/engine.rs:1051:9
24: steel::steel_vm::engine::Engine::run_raw_program_from_exprs
at ./crates/steel-core/src/steel_vm/engine.rs:1015:9
25: steel::parser::kernel::Kernel::load_program_for_comptime
at ./crates/steel-core/src/parser/kernel.rs:147:9
26: steel::compiler::compiler::Compiler::apply_const_evaluation
at ./crates/steel-core/src/compiler/compiler.rs:685:17
27: steel::compiler::compiler::Compiler::compile_raw_program
at ./crates/steel-core/src/compiler/compiler.rs:642:13
28: steel::compiler::compiler::Compiler::compile_executable
at ./crates/steel-core/src/compiler/compiler.rs:391:9
29: steel::steel_vm::engine::Engine::compile_and_run_raw_program
at ./crates/steel-core/src/steel_vm/engine.rs:1020:23
30: steel_repl::repl::finish_or_interrupt
at ./crates/steel-repl/src/repl.rs:54:15
31: steel_repl::repl::repl_base
at ./crates/steel-repl/src/repl.rs:176:25
32: steel_interpreter::run
at ./src/lib.rs:59:13
33: steel::main
at ./src/main.rs:21:5
34: core::ops::function::FnOnce::call_once
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/ops/function.rs:250:5
( I set debug = true
for this build so line numbers are present)
See bytevectors here: https://small.r7rs.org/attachment/r7rs.pdf
These could either be implemented as an enum variant in SteelVal
or as just an opaque struct.
Hi!
It should be possible to host the mdbook with generated docs using GitHub Pages. The full process is described here: https://github.com/rust-lang/mdBook/wiki/Automated-Deployment%3A-GitHub-Actions#GitHub-Pages-Deploy. This could serve well for now before more elaborate approach is needed and would make it easier to explore Steel.
I would like to be able to specify paths starting from ~
for example: ~/.local/
and it'll expand to /home/user/.local
This could be useful for interacting with other CLI tools or saving some state/data to a specific folder in the user directory.
Maybe the usage could be something like this(sorry my Scheme is nonexistant)
(expand-path "~/.local/state/helix") ;; evals to "/home/user/.local/state/helix"
On windows, I can install steel and it's cogs fine, but I can't require modules that are in current path, or giving a module via absolute path like is the default on your fork of helix with steel support showin in the image bellow.
Next is an example of using steel directly with using a module that is in the same directory, but I get an error that it can't be found.
Hello, I've noticed a behaviour incompatible with Scheme and I'm not sure whether it's intended or not:
steel> (integer? 5.0)
=> #f
racket> (integer? 5.0)
=> #t
Hence exact-integer?
makes no sense anymore
This is a great feature to have! Many scheme implementations do not have this.
This feature makes it easy to deploy steel apps.
Basically, The approach could be steel runtime + script + dependencies -> ELF binary
I am open to more thoughts on this!
Have native IO functions via ports, like so:
I just learned that there is a language server for steel. This is so great!
However, it would be even nicer if this language server would be installable using nix flakes. If this is of interest for this project, I could take care of it.
Issue encountered using Steel v 0.5.0 1fb88e5
The REPL prompt, initially defined like so λ >
, is none the less fed the newly added path name despite the loading failed.
That seems to me like unintended behaviour because of the visual noise and a possible misinterpretation leading to the belief that some symbols are actually imported in the current environment.
Run the Steel REPL:
steel
Load a wrongly named or inexistant file/path name:
:load utilities.scm
An non-blocking error occurs:
No such file or directory (os error 2)
The prompt is however fed with a non-loaded path name:
λ > (utilities.scm) >
Here is the actual result on my machine:
EDIT:
The same issue occurs when the file tentatively loaded actually exists.
Despite failing to load that said file due to a whatever compiling error, the prompt is still fed the path name, which again is an undesirable consequence.
:load <existing_file.scm>
produces the following result:
λ > :load let02.scm
error[E09]: Parse
┌─ let02.scm:15:2
│
15 │ (let ([x 3]
│ ^^^ Parse: Syntax Error: let expects an expression, found none
λ (let02.scm) >
On a side note:
Mismatch brackets
(e.g. could be called with bright().cyan()
) to determine a "notice" kind of messages to convey feed-back regarding to criticality to the user.Could be extended to the point where we would land a full nomenclatur:
notice < warning < error < fatal error.
As of right now in steel, 1/0
will panic!
λ > 1/0
In racket, 1/0
is a syntax error.
The panic appears to be in the num package.
I think here should throw a bad syntax error like in racket too, instead of letting num to panic.
Note that in racket, (/ 1 0)
is a runtime error while (/ 1 0.0)
is inf
.
In steel, both (/ 1 0)
and (/ 1 0.0)
is inf.
All of the current string primitives are case sensitive - add the equivalent -ci
versions as well, see the racket docs for inspiration.
Start here
In particular, these functions:
string=?
string<?
string<=?
string>?
string>=?
string-ci=?
string-ci<?
string-ci<=?
string-ci>?
string-ci>=?
Hello there!
I'm really curious about learning more about steel. I've already begun reading the code, though I'm not sure if I'm good enough to contribute.
For now, my main focus is to grasp the overall structure and objectives of the project.
I've started build the project and run tests, but I'm open to guidance and feedback to ensure I'm on the right path.
cargo run
works perfectly and displays the REPL
but in order to run tests i spied the CI: https://github.com/mattwparas/steel/blob/master/.github/workflows/rust.yml
so i do this:
# run-tests.sh
cd cogs
export STEEL_HOME=$HOME/.steel
echo $STEEL_HOME
mkdir -p $STEEL_HOME
cargo run -- install.scm
cd ..
cargo test --all
Everything seems to be working fine. However, I noticed some errors in the logs:
Did I miss something or forget to do anything specific?
thanks you!
See Kixiron/lasso#45. Maintainer appears to be MIA. Looked briefly at Steel's use and it seems non-trivial to factor out.
Thanks for this project, its exciting to see a scheme in Rust, I think it they compliment each other well (with regards to development vs run time, experimental vs standardized).
Although I can see the value in keeping it the future open, I was wondering what your goals for this project were?
Specifically, your thoughts on compatibly with:
Hey,
I'm not sure if it's the right way to evaluate sexps, but it seemed reasonable to report a panic occurred
λ > (eval! "(+ 1 2)")
thread 'main' panicked at crates/steel-core/src/steel_vm/engine.rs:957:50:
called `Result::unwrap()` on an `Err` value: SteelErr { repr: Repr { kind: FreeIdentifier, message: "#%function-ptr-table", span: Some(0..0), stack_trace: None } }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
P.S. Is there any way to evaluate a sexp received from read!
?
Currently parsing the signature does not take into account variadic arguments - there should be something like a RestArgs<T>
that can then deconstruct the arguments into the proper type if possible.
Something like this:
#[function(name = "foo)]
pub fn foo(a: &SteelString, b: &SteelString, c: RestArgs<SteelString>) {
...
}
I want to install to try helix with steel. I successfully installed your helix fork. But as I understand to config I need steel. So I couldn't install steel through flake.nix
.
error: builder for '/nix/store/fwshviria0fbbhbmmw27gsdh35df3qil-steel-interpreter-0.6.0.drv' failed with exit code 1;
last 10 log lines:
> Attempting to install: '#hash((#:name . "steel-websockets") (#:subdir . "libs/steel-websockets") (#:workspace-root . "../.."))
> Running dylib build in: ../libs/steel-websockets/../../libs/steel-websockets
> error[E03]: TypeMismatch
> ┌─ install.scm:11:1
> │
> 11 │
> │ Struct getter expected Ok, found Gc(UserDefinedStruct { fields: [Error: Io: No such file or directory (os error 2)], type_descriptor: StructTypeDescriptor(1) }), (Err Error: Io: No such file or direc
tory (os error 2))
>
> Error: SteelErr { repr: Repr { kind: TypeMismatch, message: "Struct getter expected Ok, found Gc(UserDefinedStruct { fields: [Error: Io: No such file or directory (os error 2)], type_descriptor: StructTypeD
escriptor(1) }), (Err Error: Io: No such file or directory (os error 2))", span: Some(2535..2544), stack_trace: Some(DehydratedStackTrace { stack_trace: [DehydratedCallContext { span: Some(0..0) }, DehydratedCallCon
text { span: Some(7212..7218) }, DehydratedCallContext { span: None }, DehydratedCallContext { span: Some(7212..7218) }, DehydratedCallContext { span: Some(2161..2172) }, DehydratedCallContext { span: Some(0..0) },
DehydratedCallContext { span: Some(1555..1563) }, DehydratedCallContext { span: Some(7212..7218) }, DehydratedCallContext { span: Some(2161..2172) }, DehydratedCallContext { span: Some(1555..1563) }, DehydratedCallC
ontext { span: Some(2182..2186) }, DehydratedCallContext { span: Some(2426..2452) }] }) } }
> /nix/store/v5irq7wvkr7kih0hhnch5nnv2dcq8c4f-stdenv-linux/setup: line 131: pop_var_context: head of shell_variables not a function context
For full logs, run 'nix log /nix/store/fwshviria0fbbhbmmw27gsdh35df3qil-steel-interpreter-0.6.0.drv'.
Missing the make-string
- see the spec for details https://small.r7rs.org/attachment/r7rs.pdf
If possible, identify any tests under cogs/r5rs.scm
that are skipped currently that need this primitive, and make sure they work.
See steel-core/src/primitives/strings.rs
for other string primitives
In scheme list values are accepted as true in boolean context. For example:
λ > (if (list 1 2) 1 2)
=> 1
But, filter only accepts #true as true value:
λ > (filter (lambda (n) (list 1 2)) (list 1 2))
=> '()
The result of the last expression should be:
λ > (filter (lambda (n) (list 1 2)) (list 1 2))
=> '(1 2)
A workaround is to use if explicitly:
λ > (filter (lambda (n) (if (list 1 2) #true #false)) (list 1 2))
=> '(1 2)
I have tested with commit 881262e,
on arch linux with rust version "rustc 1.74.0 (79e9716c9 2023-11-13) (Arch Linux rust 1:1.74.0-1)"
There is a proof of concept implementation that extracts doc comments from modules and formats into a markdown document, but this should be extended for native modules as well.
For example 1.0
should be parsed as a float, whereas 1
should be parsed as an integer.
Operations between the two should then default to use a float
It would be nice to have a proper numeric tower, right now there are integers that promote to floats at overflow - but otherwise bigints are not implemented - historically this was to avoid having to box all integers.
It might be worth implementing now, and just wrap up this crate https://docs.rs/num/latest/num/
None of the workloads should require the security of the hashmap - we should just blanket swap to use the FxHash variant instead
trying to compile commit d2d036 "Shrink the instruction size, function size (#208)" on wasm32 produces build errors with (at least) the nightly compiler:
error[E0308]: mismatched types
--> /home/user/.cargo/git/checkouts/steel-e2d1e283aa82877c/a5dc6a4/crates/steel-core/src/core/instructions.rs:150:30
|
150 | usize::from_le_bytes([a, b, c, 0, 0, 0, 0, 0])
| -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^ expected an array with a fixed size of 4 elements, found one with 8 elements
| |
| arguments to this function are incorrect
|
note: associated function defined here
--> /home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/num/mod.rs:1244:5
|
1244 | / uint_impl! {
1245 | | Self = usize,
1246 | | ActualT = u32,
1247 | | SignedT = isize,
... |
1261 | | bound_condition = " on 32-bit targets",
1262 | | }
| |_____^
= note: this error originates in the macro `uint_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0308`.
error: could not compile `steel-core` (lib) due to 1 previous error
Does the compiler run on WebAssembly (wasm)? Is such feature planned?
Add as special forms a way to provide and require files from a script
For example:
;; sort.scm
(provide sort)
(define (sort lst) ...)
(require "sort.scm")
(sort (list 6 3 5 4 1 2)) ;; '(1 2 3 4 5 6)
Only functions provided by one file should be available in a file that requires them.
Rather than attach #[function]
to every function that you want to embed, create a procedural macro that inlines the attribute based on the passed in function.
Being a somewhat lazy user of programming languages, I must admit that I'm not entirely at ease with the idea of having to navigate the nuances of installation, locating the binary, and confirming its build version...
I've been thinking about making a standard installer using a popular package manager. I'm mostly focused on myself, and right now, I'm exploring how to add something to Brew
and Nixpkgs
, which I use the most.
In this context, I find the Helix project on repology quite intriguing, and I'm pondering the idea of setting up an automated release pipeline for it.
@mattwparas, have you already considered this? Do you have any guidelines, concerns, or considerations about it?
currently nix build
and nix shell
does not work.
Running either command errors with
> error: package `clap_builder v4.5.2` cannot be built because it requires rustc 1.74 or newer, while the currently active rustc version is 1.72.1
> Either upgrade to rustc 1.74 or newer, or use
> cargo update -p [email protected] --precise ver
> where `ver` is the latest version of `clap_builder` supporting rustc 1.72.1
This is easily fixable by updating flake.lock
(i.e. calling nix flake update
).
After updating, nix build
and nix shell
now fails with a SteelErr
with message
"Struct getter expected Ok, found Gc(UserDefinedStruct { fields: [Error: Io: No such file or directory (os error 2)], type_descriptor: StructTypeDescriptor(1) }), (Err Error: Io: No such file or directory (os error 2))"
@nix { "action": "setPhase", "phase": "unpackPhase" } Running phase: unpackPhase unpacking source archive /nix/store/ry52wmz97b9il1ixg60gk1zgmjr5pqfw-source source root is source Executing cargoSetupPostUnpackHook Finished cargoSetupPostUnpackHook @nix { "action": "setPhase", "phase": "patchPhase" } Running phase: patchPhase Executing cargoSetupPostPatchHook Validating consistency between /build/source/Cargo.lock and /build/cargo-vendor-dir/Cargo.lock Finished cargoSetupPostPatchHook @nix { "action": "setPhase", "phase": "updateAutotoolsGnuConfigScriptsPhase" } Running phase: updateAutotoolsGnuConfigScriptsPhase @nix { "action": "setPhase", "phase": "configurePhase" } Running phase: configurePhase @nix { "action": "setPhase", "phase": "buildPhase" } Running phase: buildPhase Executing cargoBuildHook ++ env CC_X86_64_UNKNOWN_LINUX_GNU=/nix/store/qhpw32pz39y6i30b3vrbw5fw6zv5549f-gcc-wrapper-13.2.0/bin/cc CXX_X86_64_UNKNOWN_LINUX_GNU=/nix/store/qhpw32pz39y6i30b3vrbw5fw6zv5549f-gcc-wrapper-13.2.0/bin/c++ CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=/nix/store/qhpw32pz39y6i30b3vrbw5fw6zv5549f-gcc-wrapper-13.2.0/bin/cc CC_X86_64_UNKNOWN_LINUX_GNU=/nix/store/qhpw32pz39y6i30b3vrbw5fw6zv5549f-gcc-wrapper-13.2.0/bin/cc CXX_X86_64_UNKNOWN_LINUX_GNU=/nix/store/qhpw32pz39y6i30b3vrbw5fw6zv5549f-gcc-wrapper-13.2.0/bin/c++ CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=/nix/store/qhpw32pz39y6i30b3vrbw5fw6zv5549f-gcc-wrapper-13.2.0/bin/cc CARGO_BUILD_TARGET=x86_64-unknown-linux-gnu HOST_CC=/nix/store/qhpw32pz39y6i30b3vrbw5fw6zv5549f-gcc-wrapper-13.2.0/bin/cc HOST_CXX=/nix/store/qhpw32pz39y6i30b3vrbw5fw6zv5549f-gcc-wrapper-13.2.0/bin/c++ cargo build -j 8 --target x86_64-unknown-linux-gnu --frozen --profile release �[1m�[32m Compiling�[0m autocfg v1.1.0 �[1m�[32m Compiling�[0m proc-macro2 v1.0.78 �[1m�[32m Compiling�[0m unicode-ident v1.0.12 �[1m�[32m Compiling�[0m libc v0.2.153 �[1m�[32m Compiling�[0m cfg-if v1.0.0 �[1m�[32m Compiling�[0m smallvec v1.13.1 �[1m�[32m Compiling�[0m serde v1.0.197 �[1m�[32m Compiling�[0m parking_lot_core v0.9.9 �[1m�[32m Compiling�[0m scopeguard v1.2.0 �[1m�[32m Compiling�[0m crossbeam-utils v0.8.19 �[1m�[32m Compiling�[0m version_check v0.9.4 �[1m�[32m Compiling�[0m log v0.4.21 �[1m�[32m Compiling�[0m once_cell v1.19.0 �[1m�[32m Compiling�[0m syn v1.0.109 �[1m�[32m Compiling�[0m indexmap v1.9.3 �[1m�[32m Compiling�[0m lock_api v0.4.11 �[1m�[32m Compiling�[0m num-traits v0.2.18 �[1m�[32m Compiling�[0m cc v1.0.90 �[1m�[32m Compiling�[0m signal-hook v0.3.17 �[1m�[32m Compiling�[0m ahash v0.8.11 �[1m�[32m Compiling�[0m num-bigint v0.4.4 �[1m�[32m Compiling�[0m quote v1.0.35 �[1m�[32m Compiling�[0m hashbrown v0.12.3 �[1m�[32m Compiling�[0m typenum v1.17.0 �[1m�[32m Compiling�[0m syn v2.0.52 �[1m�[32m Compiling�[0m core_extensions v1.5.3 �[1m�[32m Compiling�[0m unicode-width v0.1.11 �[1m�[32m Compiling�[0m rustix v0.38.31 �[1m�[32m Compiling�[0m bitflags v1.3.2 �[1m�[32m Compiling�[0m getrandom v0.2.12 �[1m�[32m Compiling�[0m num-integer v0.1.46 �[1m�[32m Compiling�[0m parking_lot v0.12.1 �[1m�[32m Compiling�[0m signal-hook-registry v1.4.1 �[1m�[32m Compiling�[0m rand_core v0.6.4 �[1m�[32m Compiling�[0m mio v0.8.11 �[1m�[32m Compiling�[0m crossbeam-channel v0.5.12 �[1m�[32m Compiling�[0m slab v0.4.9 �[1m�[32m Compiling�[0m num-rational v0.4.1 �[1m�[32m Compiling�[0m zerocopy v0.7.32 �[1m�[32m Compiling�[0m core_extensions_proc_macros v1.5.3 �[1m�[32m Compiling�[0m tstr_proc_macros v0.2.2 �[1m�[32m Compiling�[0m linux-raw-sys v0.4.13 �[1m�[32m Compiling�[0m paste v1.0.14 �[1m�[32m Compiling�[0m bitflags v2.4.2 �[1m�[32m Compiling�[0m serde_json v1.0.114 �[1m�[32m Compiling�[0m tstr v0.2.3 �[1m�[32m Compiling�[0m signal-hook-mio v0.2.3 �[1m�[32m Compiling�[0m psm v0.1.21 �[1m�[32m Compiling�[0m codegen v0.2.0 �[1m�[32m Compiling�[0m abi_stable_shared v0.11.0 �[1m�[32m Compiling�[0m crossbeam-epoch v0.9.18 �[1m�[32m Compiling�[0m typed-arena v2.0.2 �[1m�[32m Compiling�[0m hashbrown v0.14.3 �[1m�[32m Compiling�[0m thiserror v1.0.57 �[1m�[32m Compiling�[0m memchr v2.7.1 �[1m�[32m Compiling�[0m itoa v1.0.10 �[1m�[32m Compiling�[0m ryu v1.0.17 �[1m�[32m Compiling�[0m utf8parse v0.2.1 �[1m�[32m Compiling�[0m bitmaps v2.1.0 �[1m�[32m Compiling�[0m crossbeam-deque v0.8.5 �[1m�[32m Compiling�[0m crossterm v0.23.2 �[1m�[32m Compiling�[0m repr_offset v0.2.2 �[1m�[32m Compiling�[0m dashmap v5.5.3 �[1m�[32m Compiling�[0m as_derive_utils v0.11.0 �[1m�[32m Compiling�[0m num-iter v0.1.44 �[1m�[32m Compiling�[0m stacker v0.1.15 �[1m�[32m Compiling�[0m crossbeam-queue v0.3.11 �[1m�[32m Compiling�[0m im-rc v15.1.0 �[1m�[32m Compiling�[0m generational-arena v0.2.9 �[1m�[32m Compiling�[0m libloading v0.7.4 �[1m�[32m Compiling�[0m termcolor v1.4.1 �[1m�[32m Compiling�[0m byteorder v1.5.0 �[1m�[32m Compiling�[0m option-ext v0.2.0 �[1m�[32m Compiling�[0m const_panic v0.2.8 �[1m�[32m Compiling�[0m futures-task v0.3.30 �[1m�[32m Compiling�[0m pin-utils v0.1.0 �[1m�[32m Compiling�[0m ppv-lite86 v0.2.17 �[1m�[32m Compiling�[0m arrayvec v0.5.2 �[1m�[32m Compiling�[0m strsim v0.11.0 �[1m�[32m Compiling�[0m futures-core v0.3.30 �[1m�[32m Compiling�[0m pin-project-lite v0.2.13 �[1m�[32m Compiling�[0m fxhash v0.2.1 �[1m�[32m Compiling�[0m dirs-sys v0.4.1 �[1m�[32m Compiling�[0m pretty v0.12.3 �[1m�[32m Compiling�[0m crossbeam v0.8.4 �[1m�[32m Compiling�[0m rand_chacha v0.3.1 �[1m�[32m Compiling�[0m coolor v0.5.0 �[1m�[32m Compiling�[0m sized-chunks v0.6.5 �[1m�[32m Compiling�[0m serde_derive v1.0.197 �[1m�[32m Compiling�[0m thiserror-impl v1.0.57 �[1m�[32m Compiling�[0m futures-macro v0.3.30 �[1m�[32m Compiling�[0m rand_xoshiro v0.6.0 �[1m�[32m Compiling�[0m minimad v0.10.0 �[1m�[32m Compiling�[0m iana-time-zone v0.1.60 �[1m�[32m Compiling�[0m either v1.10.0 �[1m�[32m Compiling�[0m home v0.5.9 �[1m�[32m Compiling�[0m chrono v0.4.35 �[1m�[32m Compiling�[0m which v4.4.2 �[1m�[32m Compiling�[0m futures-util v0.3.30 �[1m�[32m Compiling�[0m rand v0.8.5 �[1m�[32m Compiling�[0m termimad v0.21.1 �[1m�[32m Compiling�[0m steel-derive v0.5.0 (/build/source/crates/steel-derive) �[1m�[32m Compiling�[0m abi_stable_derive v0.11.3 �[1m�[32m Compiling�[0m dirs v5.0.1 �[1m�[32m Compiling�[0m codespan-reporting v0.11.1 �[1m�[32m Compiling�[0m aho-corasick v1.1.2 �[1m�[32m Compiling�[0m anstyle-parse v0.2.3 �[1m�[32m Compiling�[0m quickscope v0.2.0 �[1m�[32m Compiling�[0m futures-executor v0.3.30 �[1m�[32m Compiling�[0m dirs-sys-next v0.1.2 �[1m�[32m Compiling�[0m im-lists v0.8.0 �[1m�[32m Compiling�[0m nibble_vec v0.1.0 �[1m�[32m Compiling�[0m anstyle-query v1.0.2 �[1m�[32m Compiling�[0m radix_fmt v1.0.0 �[1m�[32m Compiling�[0m weak-table v0.3.2 �[1m�[32m Compiling�[0m anstyle v1.0.6 �[1m�[32m Compiling�[0m endian-type v0.1.2 �[1m�[32m Compiling�[0m regex-syntax v0.8.2 �[1m�[32m Compiling�[0m colorchoice v1.0.0 �[1m�[32m Compiling�[0m anstream v0.6.13 �[1m�[32m Compiling�[0m radix_trie v0.2.1 �[1m�[32m Compiling�[0m dirs-next v2.0.0 �[1m�[32m Compiling�[0m fd-lock v3.0.13 �[1m�[32m Compiling�[0m nix v0.25.1 �[1m�[32m Compiling�[0m lazy_static v1.4.0 �[1m�[32m Compiling�[0m clap_lex v0.7.0 �[1m�[32m Compiling�[0m unicode-segmentation v1.11.0 �[1m�[32m Compiling�[0m heck v0.4.1 �[1m�[32m Compiling�[0m clap_derive v4.5.0 �[1m�[32m Compiling�[0m regex-automata v0.4.6 �[1m�[32m Compiling�[0m rustyline v10.1.1 �[1m�[32m Compiling�[0m clap_builder v4.5.2 �[1m�[32m Compiling�[0m steel-gen v0.2.0 (/build/source/crates/steel-gen) �[1m�[32m Compiling�[0m regex v1.10.3 �[1m�[32m Compiling�[0m num-complex v0.4.5 �[1m�[32m Compiling�[0m hashbrown v0.13.2 �[1m�[32m Compiling�[0m steel-core v0.6.0 (/build/source/crates/steel-core) �[1m�[32m Compiling�[0m bincode v1.3.3 �[1m�[32m Compiling�[0m lasso v0.7.2 �[1m�[32m Compiling�[0m abi_stable v0.11.3 �[1m�[32m Compiling�[0m num v0.4.1 �[1m�[32m Compiling�[0m colored v2.1.0 �[1m�[32m Compiling�[0m steel-parser v0.6.0 (/build/source/crates/steel-parser) �[1m�[32m Compiling�[0m rustyline-derive v0.7.0 �[1m�[32m Compiling�[0m is-terminal v0.4.12 �[1m�[32m Compiling�[0m humantime v2.1.0 �[1m�[32m Compiling�[0m clap v4.5.2 �[1m�[32m Compiling�[0m env_logger v0.10.2 �[1m�[32m Compiling�[0m async-ffi v0.5.0 �[1m�[32m Compiling�[0m steel-repl v0.6.0 (/build/source/crates/steel-repl) �[1m�[32m Compiling�[0m steel-doc v0.6.0 (/build/source/crates/steel-doc) �[1m�[32m Compiling�[0m steel-interpreter v0.6.0 (/build/source) �[1m�[32m Finished�[0m release [optimized] target(s) in 3m 49s Executing cargoInstallPostBuildHook Finished cargoInstallPostBuildHook Finished cargoBuildHook buildPhase completed in 3 minutes 50 seconds @nix { "action": "setPhase", "phase": "installPhase" } Running phase: installPhase Executing cargoInstallHook /build/source/cogs /build/source cogs directory does not exist, creating now... Package is not currently installed. => Installing: '#hash((package-name . steel/lists) (path . "/build/source/cogs/lists") (version . "0.1.0") (dependencies . ())) => Copied package over to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/lists ✅ Installed package to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/listsPackage is not currently installed.
=> Installing: '#hash((path . "/build/source/cogs/command-line") (version . "0.1.0") (package-name . steel/command-line) (dependencies . ()))
=> Copied package over to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/command-line
✅ Installed package to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/command-linePackage is not currently installed.
=> Installing: '#hash((package-name . steel/sorting) (version . "0.1.0") (dependencies . ()) (path . "/build/source/cogs/sorting"))
=> Copied package over to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/sorting
✅ Installed package to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/sortingPackage is not currently installed.
=> Installing: '#hash((dependencies . ()) (package-name . steel/collections) (path . "/build/source/cogs/collections") (version . "0.1.0"))
=> Copied package over to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/collections
✅ Installed package to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/collectionsPackage is not currently installed.
=> Installing: '#hash((package-name . steel/tests) (dependencies . ()) (version . "0.1.0") (path . "/build/source/cogs/tests"))
=> Copied package over to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/tests
✅ Installed package to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/testsPackage is not currently installed.
=> Installing: '#hash((version . "0.1.0") (path . "/build/source/cogs/srfi") (package-name . srfi) (dependencies . ()))
=> Copied package over to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/srfi
✅ Installed package to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/srfiPackage is not currently installed.
=> Installing: '#hash((dependencies . ()) (package-name . steel/fs) (version . "0.1.0") (path . "/build/source/cogs/fs"))
=> Copied package over to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/fs
✅ Installed package to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/fsPackage is not currently installed.
=> Installing: '#hash((version . "0.1.0") (package-name . steel/time) (path . "/build/source/cogs/time") (dependencies . ()))
=> Copied package over to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/time
✅ Installed package to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel/timePackage is not currently installed.
=> Installing: '#hash((path . "/build/source/cogs/installer") (dependencies . ()) (version . "0.1.0") (package-name . installer))
=> Copied package over to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/installer
✅ Installed package to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/installerPackage is not currently installed.
=> Installing: '#hash((path . "/build/source/cogs/slack") (version . "0.1.0") (dependencies . ('#hash((#:path . "../libs/steel-websockets") (#:name . steel-websockets)) '#hash((#:path . "../libs/steel-webrequests") (#:name . steel-webrequests)))) (package-name . slack/websocket))
=> Copied package over to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/slack/websocket
=> Installing: '#hash((version . "0.1.0") (package-name . steel-websockets) (dependencies . ()) (path . "../libs/steel-websockets") (dylibs . ('#hash((#:name . "steel-websockets") (#:workspace-root . "../..") (#:subdir . "libs/steel-websockets")))))
=> Copied package over to: /nix/store/lh4y0sjnnqqmwmrzn91lbhfqim1md3ap-steel-interpreter-0.6.0/lib/cogs/steel-websockets
Attempting to install: '#hash((#:name . "steel-websockets") (#:workspace-root . "../..") (#:subdir . "libs/steel-websockets"))
Running dylib build in: ../libs/steel-websockets/../../libs/steel-websockets
�[0m�[1m�[38;5;9merror[E03]�[0m�[1m: TypeMismatch�[0m
�[0m�[34m┌─�[0m install.scm:11:1
�[0m�[34m│�[0m
�[0m�[34m11�[0m �[0m�[34m│�[0m
�[0m�[34m│�[0m �[0m�[31mStruct getter expected Ok, found Gc(UserDefinedStruct { fields: [Error: Io: No such file or directory (os error 2)], type_descriptor: StructTypeDescriptor(1) }), (Err Error: Io: No such file or directory (os error 2))�[0mError: SteelErr { repr: Repr { kind: TypeMismatch, message: "Struct getter expected Ok, found Gc(UserDefinedStruct { fields: [Error: Io: No such file or directory (os error 2)], type_descriptor: StructTypeDescriptor(1) }), (Err Error: Io: No such file or directory (os error 2))", span: Some(2535..2544), stack_trace: Some(DehydratedStackTrace { stack_trace: [DehydratedCallContext { span: Some(0..0) }, DehydratedCallContext { span: Some(0..0) }, DehydratedCallContext { span: None }, DehydratedCallContext { span: Some(0..0) }, DehydratedCallContext { span: Some(2161..2172) }, DehydratedCallContext { span: Some(0..0) }, DehydratedCallContext { span: Some(1555..1563) }, DehydratedCallContext { span: Some(0..0) }, DehydratedCallContext { span: Some(2161..2172) }, DehydratedCallContext { span: Some(1555..1563) }, DehydratedCallContext { span: Some(2182..2186) }, DehydratedCallContext { span: Some(2426..2452) }] }) } }
/nix/store/v099hqvw5z87423p4hz1vfhzaqa07dii-stdenv-linux/setup: line 131: pop_var_context: head of shell_variables not a function context
PS: the popd
in line 41 in flake.nix
seems to throw an error too, see the last line of the log
EDIT: I investigated this further. This is not a nix flake
error! Instead this seems to originate from running cargo run -- install.scm
from contributing.scm
too! To me it looks like steel-websockets
or steel-regex
fails to install (depending on which machine I use)
See here for the module
It is a little opaque - the functions that return Result
return a struct to rust that is Ok
or Err
, which makes it non obvious how to use. On top of that, some of the functions are builders, and some act via mutation. First is to probably add some documentation to these functions, and then after that we should implement a module in the cogs
directory that wraps up some of the more low level functions into something a bit more idiomatic.
For example, capturing std out into a string is a little non obvious:
(define (with-stdout-piped command)
(set-piped-stdout! command)
command)
(~> (command "git" (list "check-ignore" "target"))
(with-stdout-piped)
(spawn-process)
(Ok->value)
(wait->stdout)
(Ok->value))
Hello, I appreciate your work with Steel and as a Plugin system!
Testing the plugin system (great work btw) I founded a misunderstanding about how to integrate this with Helix.
In STEEL.md (https://github.com/mattwparas/helix) you mentioned using the master branch on steel, but in the master branch it has a conflict with steel-core dependency
The syntax-rules
implementation is not done in scheme, but instead is done natively in Rust. There is quite a bit of room for improvement here. For example, the ability to deconstruct pairs on patterns is not supported, like so for this let implementation https://www.scheme.com/tspl2d/syntax.html:
(define-syntax let*
(syntax-rules ()
((_ () e1 e2 ...) (let () e1 e2 ...))
((_ ((i1 v1) (i2 v2) ...) e1 e2 ...)
(let ((i1 v1))
(let* ((i2 v2) ...) e1 e2 ...)))))
The issue here is the (i2 v2) ...
- The current implementation only supports ...
on single values, not on a pair.
There are some (unsafe) values that I need to insert into the engine that have the lifetime of a single script execution. In order to maintain my invariants, I would like to be able to deregister an external value, so that I can remove it from the engine after my script completes.
Be able to define structs in a similar fashion to Racket
I was looking at the doc and how the doc are generated.
It appears that various built-in functions are missing in the generated documentation (the book) and the built-in (help indent)
, such as cons
, reverse
...
All these are missing, (help cons)
doesn't print CONS_DOC
steel/crates/steel-core/src/primitives/lists.rs
Lines 92 to 95 in d81f428
Tagging enums with the #[steel]
should result in constructors and predicates (potentially, getters and setters) for the enum variants. For example, this enum:
#[steel]
pub enum Foo {
Bar,
Baz(usize)
}
Should result in the following scheme functions:
Foo?
Foo-Bar?
Foo-Baz?
Foo-Bar
Foo-Baz
...
(Foo-Bar) ;; <#Foo>
(Foo-Baz 15) ;; <#Foo>
...
Work still needs to be done to decide how to get and set structs/enums with unnamed fields.
At the moment, all of the dylibs are loaded at interpreter startup - we probably want to only load the dylib once there is actually a call to require-builtin
that references a dylib.
Another concern is that compilation requires loading the dylib, which we also don't want. This is fine for use cases when compilation happens directly before running the actual code, but if we're compiling ahead of time or checking the bytecode or ast dump, we don't want to have to load the dylib. We'll need some kind of primitive to expose the expected API of the dylib rather than load the dylib to inspect the module API within it to allow compilation to succeed in an environment where the dylib doesn't exist, perhaps something like
;; Contains the functions, "foo" and "bar"
(require-builtin external-dylib)
(declare "foo")
(declare "bar")
declare
should just reserve a slot in the global env for the value, but otherwise shouldn't do anything.
As per the doc it should be "a b" but it is " a b"
λ > (to-string "a" "b")
=> " a b"
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.