Skip to content

Commit

Permalink
Support String#downcase.
Browse files Browse the repository at this point in the history
Refine Process.#clock_get_time.
  • Loading branch information
sisshiki1969 committed Aug 17, 2023
1 parent 6dc051e commit 85507ca
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 100 deletions.
36 changes: 33 additions & 3 deletions monoruby/src/executor/builtins/process.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use num::ToPrimitive;

use crate::*;

use self::clock_gettime::TimeSpec;
Expand Down Expand Up @@ -74,11 +76,39 @@ fn pid(_vm: &mut Executor, _globals: &mut Globals, _lfp: LFP, _arg: Arg) -> Resu
///
/// [https://docs.ruby-lang.org/ja/latest/method/Process/m/clock_gettime.html]
#[monoruby_builtin]
fn clock_gettime(_vm: &mut Executor, globals: &mut Globals, _lfp: LFP, arg: Arg) -> Result<Value> {
fn clock_gettime(_vm: &mut Executor, globals: &mut Globals, lfp: LFP, _arg: Arg) -> Result<Value> {
MonorubyErr::check_number_of_arguments_range(lfp.arg_len(), 1..=2)?;
let unit = if lfp.arg_len() == 1 {
IdentId::FLOAT_SECOND
} else {
match lfp.arg(1).try_symbol() {
Some(id) => id,
None => {
return Err(MonorubyErr::argumenterr(format!(
"unexpected unit: {}",
globals.to_s(lfp.arg(1))
)))
}
}
};
let mut tp = TimeSpec::default();
let clk_id = arg[0].coerce_to_i64(globals)? as i32;
let clk_id = lfp.arg(0).coerce_to_i64(globals)? as i32;
clock_gettime::clock_gettime(clk_id, &mut tp);
Ok(Value::float(tp.to_f64()))
Ok(match unit {
IdentId::FLOAT_SECOND => Value::float(tp.sec().to_f64().unwrap()),
IdentId::FLOAT_MILLISECOND => Value::float(tp.millisec().to_f64().unwrap()),
IdentId::FLOAT_MICROSECOND => Value::float(tp.microsec().to_f64().unwrap()),
IdentId::SECOND => Value::integer(tp.sec()),
IdentId::MILLISECOND => Value::integer(tp.millisec()),
IdentId::MICROSECOND => Value::integer(tp.microsec()),
IdentId::NANOSECOND => Value::integer(tp.nanosec()),
_ => {
return Err(MonorubyErr::argumenterr(format!(
"unexpected unit: {}",
globals.to_s(lfp.arg(1))
)))
}
})
}

#[cfg(test)]
Expand Down
23 changes: 16 additions & 7 deletions monoruby/src/executor/builtins/process/clock_gettime.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
use num::ToPrimitive;

#[derive(Debug, Clone, Default)]
#[repr(C)]
pub struct TimeSpec {
pub(super) struct TimeSpec {
pub tv_sec: i64,
pub tv_nsec: i64,
}

impl TimeSpec {
pub fn to_f64(&self) -> f64 {
self.tv_sec.to_f64().unwrap() + self.tv_nsec.to_f64().unwrap() / 1e9
pub fn sec(&self) -> i64 {
self.tv_sec + self.tv_nsec / 1000_000_000
}

pub fn millisec(&self) -> i64 {
self.tv_sec * 1000 + self.tv_nsec / 1000_000
}

pub fn microsec(&self) -> i64 {
self.tv_sec * 1000_000 + self.tv_nsec / 1000
}

pub fn nanosec(&self) -> i64 {
self.tv_sec * 1000_000_000 + self.tv_nsec
}
}

pub fn clock_gettime(clk_id: i32, tp: &mut TimeSpec) {
pub(super) fn clock_gettime(clk_id: i32, tp: &mut TimeSpec) {
unsafe {
let res = libc::clock_gettime(clk_id, tp as *mut _ as *mut libc::timespec);
assert!(res == 0);
Expand Down
19 changes: 18 additions & 1 deletion monoruby/src/executor/builtins/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub(super) fn init(globals: &mut Globals) {
globals.define_builtin_func(STRING_CLASS, "intern", to_sym, 0);
globals.define_builtin_func(STRING_CLASS, "to_sym", to_sym, 0);
globals.define_builtin_func(STRING_CLASS, "upcase", upcase, 0);
globals.define_builtin_func(STRING_CLASS, "downcase", downcase, 0);
globals.define_builtin_func(STRING_CLASS, "tr", tr, 2);
}

Expand Down Expand Up @@ -1019,6 +1020,21 @@ fn upcase(_vm: &mut Executor, _globals: &mut Globals, lfp: LFP, _arg: Arg) -> Re
Ok(Value::string_from_vec(s.into_bytes()))
}

//
/// ### String#downcase
///
/// - downcase([NOT SUPPORTED]*options) -> String
///
/// [https://docs.ruby-lang.org/ja/latest/method/String/i/downcase.html]
#[monoruby_builtin]
fn downcase(_vm: &mut Executor, _globals: &mut Globals, lfp: LFP, _arg: Arg) -> Result<Value> {
let len = lfp.arg_len();
MonorubyErr::check_number_of_arguments(len, 0)?;
let self_val = lfp.self_val();
let s = self_val.as_str().as_ref().to_lowercase();
Ok(Value::string_from_vec(s.into_bytes()))
}

///
/// ### String#tr
///
Expand Down Expand Up @@ -1317,6 +1333,7 @@ mod test {

#[test]
fn upcase() {
run_test(r"'AkrFju35]['.upcase");
run_test(r"'AkrFj妖精u35]['.upcase");
run_test(r"'AkrFj妖精u35]['.downcase");
}
}
4 changes: 2 additions & 2 deletions monoruby/src/executor/builtins/struct_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ fn initialize(_vm: &mut Executor, globals: &mut Globals, lfp: LFP, _: Arg) -> Re
return Err(MonorubyErr::argumenterr("Struct size differs."));
};
for (i, val) in lfp.iter().enumerate() {
let id = members[i].as_symbol();
let id = members[i].try_symbol().unwrap();
let ivar_name = IdentId::add_ivar_prefix(id);
globals.set_ivar(self_val, ivar_name, val)?;
}
Expand All @@ -90,7 +90,7 @@ fn inspect(_vm: &mut Executor, globals: &mut Globals, lfp: LFP, _arg: Arg) -> Re

if name.len() != 0 {
for x in name.iter() {
let name = x.as_symbol();
let name = x.try_symbol().unwrap();
let ivar_name = IdentId::add_ivar_prefix(name);
let val = match globals.get_ivar(self_val, ivar_name) {
Some(v) => globals.inspect(v),
Expand Down
4 changes: 2 additions & 2 deletions monoruby/src/executor/compiler/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,8 +687,8 @@ pub(super) extern "C" fn alias_method(
old: Value,
meta: Meta,
) -> Option<Value> {
let new = new.as_symbol();
let old = old.as_symbol();
let new = new.try_symbol().unwrap();
let old = old.try_symbol().unwrap();
match if meta.is_class_def() {
globals.alias_method_for_class(self_val.as_class().id(), new, old)
} else {
Expand Down
7 changes: 2 additions & 5 deletions monoruby/src/executor/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,8 @@ impl Globals {
.unwrap()
.node;

let mut lib: Vec<String> = Value::from_ast2(&nodes)
.as_array()
.iter()
.map(|v| v.as_string())
.collect();
let lib: Array = Value::from_ast2(&nodes).into();
let mut lib: Vec<String> = lib.iter().map(|v| v.as_string()).collect();
globals.lib_directories.append(&mut lib);
// set constants
let pcg_name = env!("CARGO_PKG_NAME");
Expand Down
88 changes: 51 additions & 37 deletions monoruby/src/id_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ impl IdentId {
pub const _BAND: IdentId = id!(33);
pub const _BXOR: IdentId = id!(34);
pub const _UMINUS: IdentId = id!(35);
pub const FLOAT_SECOND: IdentId = id!(36);
pub const SECOND: IdentId = id!(37);
pub const FLOAT_MILLISECOND: IdentId = id!(38);
pub const MILLISECOND: IdentId = id!(39);
pub const FLOAT_MICROSECOND: IdentId = id!(40);
pub const MICROSECOND: IdentId = id!(41);
pub const NANOSECOND: IdentId = id!(42);
}

impl IdentId {
Expand Down Expand Up @@ -181,47 +188,54 @@ impl IdentifierTable {
pub(crate) fn new() -> Self {
let mut table = IdentifierTable {
rev_table: HashMap::default(),
table: vec![String::new(); 40],
table: vec![String::new(); 50],
};
table.set_ident_id("initialize", IdentId::INITIALIZE);
table.set_ident_id("Object", IdentId::OBJECT);
table.set_ident_id("new", IdentId::NEW);
table.set_ident_id("name", IdentId::NAME);
table.set_ident_id("+", IdentId::_ADD);
table.set_ident_id("-", IdentId::_SUB);
table.set_ident_id("*", IdentId::_MUL);
table.set_ident_id("**", IdentId::_POW);
table.set_ident_id("<<", IdentId::_SHL);
table.set_ident_id("%", IdentId::_REM);
table.set_ident_id("==", IdentId::_EQ);
table.set_ident_id("!=", IdentId::_NEQ);
table.set_ident_id(">", IdentId::_GT);
table.set_ident_id(">=", IdentId::_GE);
table.set_ident_id("/", IdentId::_DIV);
table.set_ident_id("<", IdentId::_LT);
table.set_ident_id("<=", IdentId::_LE);
table.set_ident_id("<=>", IdentId::_CMP);
table.set_ident_id("===", IdentId::_TEQ);
table.set_ident_id("/enum", IdentId::_ENUM_FUNC);
table.set_ident_id("[]", IdentId::_INDEX);
table.set_ident_id("[]=", IdentId::_INDEX_ASSIGN);
table.set_ident_id("to_s", IdentId::TO_S);
table.set_ident_id(">>", IdentId::_SHR);
table.set_ident_id("/alias_method", IdentId::_ALIAS_METHOD);
table.set_ident_id("method_missing", IdentId::_METHOD_MISSING);
table.set_ident_id("each", IdentId::EACH);
table.set_ident_id("map", IdentId::MAP);
table.set_ident_id("/name", IdentId::_NAME);
table.set_ident_id("...", IdentId::_DOT3);
table.set_ident_id("/main", IdentId::_MAIN);
table.set_ident_id("|", IdentId::_BOR);
table.set_ident_id("&", IdentId::_BAND);
table.set_ident_id("^", IdentId::_BXOR);
table.set_ident_id("-@", IdentId::_UMINUS);
table.set_id("initialize", IdentId::INITIALIZE);
table.set_id("Object", IdentId::OBJECT);
table.set_id("new", IdentId::NEW);
table.set_id("name", IdentId::NAME);
table.set_id("+", IdentId::_ADD);
table.set_id("-", IdentId::_SUB);
table.set_id("*", IdentId::_MUL);
table.set_id("**", IdentId::_POW);
table.set_id("<<", IdentId::_SHL);
table.set_id("%", IdentId::_REM);
table.set_id("==", IdentId::_EQ);
table.set_id("!=", IdentId::_NEQ);
table.set_id(">", IdentId::_GT);
table.set_id(">=", IdentId::_GE);
table.set_id("/", IdentId::_DIV);
table.set_id("<", IdentId::_LT);
table.set_id("<=", IdentId::_LE);
table.set_id("<=>", IdentId::_CMP);
table.set_id("===", IdentId::_TEQ);
table.set_id("/enum", IdentId::_ENUM_FUNC);
table.set_id("[]", IdentId::_INDEX);
table.set_id("[]=", IdentId::_INDEX_ASSIGN);
table.set_id("to_s", IdentId::TO_S);
table.set_id(">>", IdentId::_SHR);
table.set_id("/alias_method", IdentId::_ALIAS_METHOD);
table.set_id("method_missing", IdentId::_METHOD_MISSING);
table.set_id("each", IdentId::EACH);
table.set_id("map", IdentId::MAP);
table.set_id("/name", IdentId::_NAME);
table.set_id("...", IdentId::_DOT3);
table.set_id("/main", IdentId::_MAIN);
table.set_id("|", IdentId::_BOR);
table.set_id("&", IdentId::_BAND);
table.set_id("^", IdentId::_BXOR);
table.set_id("-@", IdentId::_UMINUS);
table.set_id("float_second", IdentId::FLOAT_SECOND);
table.set_id("second", IdentId::SECOND);
table.set_id("float_millisecond", IdentId::FLOAT_MILLISECOND);
table.set_id("millisecond", IdentId::MILLISECOND);
table.set_id("float_microsecond", IdentId::FLOAT_MICROSECOND);
table.set_id("microsecond", IdentId::MICROSECOND);
table.set_id("nanosecond", IdentId::NANOSECOND);
table
}

fn set_ident_id(&mut self, name: &str, id: IdentId) {
fn set_id(&mut self, name: &str, id: IdentId) {
self.rev_table.insert(name.to_string(), id);
self.table[id.to_usize() - 1] = name.to_string();
}
Expand Down
Loading

0 comments on commit 85507ca

Please sign in to comment.