Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions runtime/vm/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,12 @@ impl VM {

Opcode::Call => {
if let Some(Operand::Count(arg_count)) = inst_operands.first() {
let mut args = Vec::new();
// ⚡ Bolt Performance Optimization:
// Pre-allocate the argument vector capacity up to the available stack size.
// This avoids dynamic reallocation overhead in the hot VM loop while
// preventing potential OOM panics from malformed bytecode with huge argument counts.
let mut args =
Vec::with_capacity((*arg_count as usize).min(self.stack.len()));
for _ in 0..*arg_count {
args.push(self.stack.pop()?);
}
Expand Down Expand Up @@ -693,7 +698,11 @@ impl VM {

Opcode::MakeList => {
if let Some(Operand::Count(n)) = inst_operands.first() {
let mut items = Vec::new();
// ⚡ Bolt Performance Optimization:
// Pre-allocate the list capacity up to the available stack size.
// This avoids dynamic reallocation overhead in the hot VM loop while
// preventing potential OOM panics from malformed bytecode with huge item counts.
let mut items = Vec::with_capacity((*n as usize).min(self.stack.len()));
for _ in 0..*n {
items.push(self.stack.pop()?);
}
Expand All @@ -709,7 +718,14 @@ impl VM {

Opcode::MakeMap => {
if let Some(Operand::Count(n)) = inst_operands.first() {
let mut entries = indexmap::IndexMap::new();
// ⚡ Bolt Performance Optimization:
// Pre-allocate the map capacity up to half the available stack size
// (since each entry consumes a key and a value on the stack).
// This avoids dynamic reallocation overhead in the hot VM loop while
// preventing potential OOM panics from malformed bytecode with huge item counts.
let mut entries = indexmap::IndexMap::with_capacity(
(*n as usize).min(self.stack.len() / 2),
);
for _ in 0..*n {
let val = self.stack.pop()?;
let key_val = self.stack.pop()?;
Expand Down
2 changes: 1 addition & 1 deletion stdlib/src/net.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::net_handler::{tcp_connect_fn, tcp_listen_fn, tcp_recv_fn, tcp_send_fn};
use crate::{StdFunction, StdlibModule, StdlibRegistry};
use std::collections::HashMap;
use std::rc::Rc;
use techscript_runtime::context::Capability;
use crate::net_handler::{tcp_listen_fn, tcp_connect_fn, tcp_send_fn, tcp_recv_fn};

impl StdlibRegistry {
pub fn register_net(&mut self) {
Expand Down
15 changes: 7 additions & 8 deletions stdlib/src/net_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,13 @@ pub fn tcp_connect_fn(
) -> Result<RuntimeValue, RuntimeError> {
let ip = args[0].try_into_string()?;
let port = args[1].try_into_int()?;
let stream =
std::net::TcpStream::connect(format!("{}:{}", ip, port)).map_err(|e| {
RuntimeError::new(
RuntimeErrorKind::InvalidOperation(format!("TCP connect error: {}", e)),
None,
None,
)
})?;
let stream = std::net::TcpStream::connect(format!("{}:{}", ip, port)).map_err(|e| {
RuntimeError::new(
RuntimeErrorKind::InvalidOperation(format!("TCP connect error: {}", e)),
None,
None,
)
})?;
let handle_id = ctx.resources.borrow_mut().insert(stream);
let mut stream_map = IndexMap::new();
stream_map.insert("ip".to_string(), RuntimeValue::Str(ip));
Expand Down
87 changes: 69 additions & 18 deletions stdlib/src/strings.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use crate::{StdFunction, StdlibModule, StdlibRegistry};
use std::collections::HashMap;
use std::rc::Rc;
use techscript_runtime::{error::RuntimeError, error::RuntimeErrorKind, value::RuntimeValue};
use techscript_runtime::RuntimeContext;
use techscript_runtime::{error::RuntimeError, error::RuntimeErrorKind, value::RuntimeValue};

fn trim(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
let s = args[0].try_into_string()?;
Ok(RuntimeValue::Str(s.trim().to_string()))
}

fn replace(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn replace(
_ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let source = args[0].try_into_string()?;
let from = args[1].try_into_string()?;
let to = args[2].try_into_string()?;
Expand Down Expand Up @@ -49,50 +52,77 @@ fn join(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeVal
}
}

fn to_lower(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn to_lower(
_ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let s = args[0].try_into_string()?;
Ok(RuntimeValue::Str(s.to_lowercase()))
}

fn to_upper(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn to_upper(
_ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let s = args[0].try_into_string()?;
Ok(RuntimeValue::Str(s.to_uppercase()))
}

fn contains(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn contains(
_ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let s = args[0].try_into_string()?;
let sub = args[1].try_into_string()?;
Ok(RuntimeValue::Bool(s.contains(&sub)))
}

fn from_int(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn from_int(
_ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let val = args[0].try_into_int()?;
Ok(RuntimeValue::Str(val.to_string()))
}

fn from_float(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn from_float(
_ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let val = args[0].try_into_float()?;
Ok(RuntimeValue::Str(val.to_string()))
}

fn from_bool(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn from_bool(
_ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let val = args[0].try_into_bool()?;
Ok(RuntimeValue::Str(val.to_string()))
}

fn trim(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn trim(
_ctx: &mut techscript_runtime::RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let s = args[0].try_into_string()?;
Ok(RuntimeValue::Str(s.trim().to_string()))
}

fn replace(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn replace(
_ctx: &mut techscript_runtime::RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let source = args[0].try_into_string()?;
let from = args[1].try_into_string()?;
let to = args[2].try_into_string()?;
Ok(RuntimeValue::Str(source.replace(&from, &to)))
}

fn split(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn split(
_ctx: &mut techscript_runtime::RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let s = args[0].try_into_string()?;
let pat = args[1].try_into_string()?;
let parts: Vec<RuntimeValue> = s
Expand All @@ -105,7 +135,10 @@ fn split(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>)
})
}

fn join(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn join(
_ctx: &mut techscript_runtime::RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let sep = args[1].try_into_string()?;
if let RuntimeValue::List { items, .. } = &args[0] {
let mut str_parts = Vec::new();
Expand All @@ -125,33 +158,51 @@ fn join(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>)
}
}

fn to_lower(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn to_lower(
_ctx: &mut techscript_runtime::RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let s = args[0].try_into_string()?;
Ok(RuntimeValue::Str(s.to_lowercase()))
}

fn to_upper(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn to_upper(
_ctx: &mut techscript_runtime::RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let s = args[0].try_into_string()?;
Ok(RuntimeValue::Str(s.to_uppercase()))
}

fn contains(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn contains(
_ctx: &mut techscript_runtime::RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let s = args[0].try_into_string()?;
let sub = args[1].try_into_string()?;
Ok(RuntimeValue::Bool(s.contains(&sub)))
}

fn from_int(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn from_int(
_ctx: &mut techscript_runtime::RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let val = args[0].try_into_int()?;
Ok(RuntimeValue::Str(val.to_string()))
}

fn from_float(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn from_float(
_ctx: &mut techscript_runtime::RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let val = args[0].try_into_float()?;
Ok(RuntimeValue::Str(val.to_string()))
}

fn from_bool(_ctx: &mut techscript_runtime::RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn from_bool(
_ctx: &mut techscript_runtime::RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let val = args[0].try_into_bool()?;
Ok(RuntimeValue::Str(val.to_string()))
}
Expand Down
66 changes: 45 additions & 21 deletions stdlib/src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,10 @@ fn dsl_to_html_inner(val: &RuntimeValue, html: &mut String) {
}
}

fn web_start(ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn web_start(
ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
if !ctx.config.capabilities.contains(&Capability::Network) {
return Err(RuntimeError::new(
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(
Expand Down Expand Up @@ -414,17 +417,26 @@ fn web_start(ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<Runtim
}
}
});
Ok(RuntimeValue::Str(format!("Server started on port {}", port)))
Ok(RuntimeValue::Str(format!(
"Server started on port {}",
port
)))
}

fn web_page(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn web_page(
_ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let _path = args[0].to_string();
let content = args[1].to_string();
*PAGE_CONTENT.lock().unwrap() = content;
Ok(RuntimeValue::Null)
}

fn web_serve(ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn web_serve(
ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
if !ctx.config.capabilities.contains(&Capability::Network) {
return Err(RuntimeError::new(
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(
Expand Down Expand Up @@ -474,21 +486,33 @@ fn web_serve(ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<Runtim
}
}
});
Ok(RuntimeValue::Str(format!("Server started on port {}", port)))
Ok(RuntimeValue::Str(format!(
"Server started on port {}",
port
)))
}

fn web_stop(_ctx: &mut RuntimeContext, _args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn web_stop(
_ctx: &mut RuntimeContext,
_args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
SERVER_RUNNING.store(false, Ordering::SeqCst);
Ok(RuntimeValue::Null)
}

fn web_set_content(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn web_set_content(
_ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let new_content = args[0].to_string();
*PAGE_CONTENT.lock().unwrap() = new_content;
Ok(RuntimeValue::Str("Content updated".to_string()))
}

fn web_fetch(ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn web_fetch(
ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
if !ctx.config.capabilities.contains(&Capability::Network) {
return Err(RuntimeError::new(
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(
Expand All @@ -510,35 +534,32 @@ fn web_fetch(ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<Runtim
));
}

let agent = ureq::builder()
.resolver(SafeResolver)
.redirects(0)
.build();
let body = agent.get(&url)
let agent = ureq::builder().resolver(SafeResolver).redirects(0).build();
let body = agent
.get(&url)
.call()
.map_err(|e| {
RuntimeError::new(
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(
e.to_string(),
),
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(e.to_string()),
None,
None,
)
})?
.into_string()
.map_err(|e| {
RuntimeError::new(
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(
e.to_string(),
),
techscript_runtime::error::RuntimeErrorKind::InvalidOperation(e.to_string()),
None,
None,
)
})?;
Ok(RuntimeValue::Str(body))
}

fn web_render_html(ctx: &mut RuntimeContext, _args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn web_render_html(
ctx: &mut RuntimeContext,
_args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let env = ctx.global_env.borrow();
let blocks = match env.lookup("_dsl_blocks") {
Ok(RuntimeValue::List { items, .. }) => items.borrow().clone(),
Expand All @@ -551,7 +572,10 @@ fn web_render_html(ctx: &mut RuntimeContext, _args: Vec<RuntimeValue>) -> Result
Ok(RuntimeValue::Str(html))
}

fn web_render_dsl(_ctx: &mut RuntimeContext, args: Vec<RuntimeValue>) -> Result<RuntimeValue, RuntimeError> {
fn web_render_dsl(
_ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
let html = dsl_to_html(&args[0]);
Ok(RuntimeValue::Str(html))
}
Expand Down
Loading
Loading