diff --git a/selib/math.yard b/selib/math.yard new file mode 100644 index 0000000..dc0c825 --- /dev/null +++ b/selib/math.yard @@ -0,0 +1,24 @@ +@pragma(once) + +@feature(conv, math) +@author(Sven Vogel) + +floor(x:rat) = rat { + to_rat(to_int(x)) +} + +round(x:rat) = rat { + to_rat(to_int(x + 0.5)) +} + +ceil(x:rat) = rat { + to_rat(to_int(x + 1.0)) +} + +fract(x:rat) = rat { + x - floor(x) +} + +log(x:rat, b:rat) = rat { + log(x) / log(b) +} \ No newline at end of file diff --git a/src/builtin/mod.rs b/src/builtin/mod.rs new file mode 100644 index 0000000..65128cd --- /dev/null +++ b/src/builtin/mod.rs @@ -0,0 +1,52 @@ +/// module for builtin functons +/// and the SENI-module +use crate::{parser::data::{Declr, Func}, vmrt::Data}; + +use self::modules::Module; + +pub mod modules; + +type Function = &'static dyn Fn(&[Data]) -> Result, ()>; + +#[derive(Clone)] +pub struct BuiltinFun { + declr: Declr<'static>, + func: Function +} + +impl BuiltinFun { + + pub fn declr(&self) -> Declr<'static> { + self.declr.clone() + } + + pub fn func(&self) -> crate::parser::data::Func<'static> { + Func { + expr: None, + is_builtin: true, + raw: None + } + } + + pub fn get_function(&self) -> Function { + self.func + } +} + +pub fn get_builtin_funs(mods: &[Module]) -> Vec { + let mut funs = vec![ + BuiltinFun { + declr: Declr::generate_builtin("say_hello", vec![], None), + func: &say_hello + }, + ]; + + funs.append(&mut modules::get_submodules(mods)); + + return funs; +} + +fn say_hello(_args: &[Data]) -> Result, ()> { + println!("hello!"); + Ok(None) +} \ No newline at end of file diff --git a/src/builtin/modules/conv.rs b/src/builtin/modules/conv.rs new file mode 100644 index 0000000..d511431 --- /dev/null +++ b/src/builtin/modules/conv.rs @@ -0,0 +1,50 @@ +use crate::{token::Prim, parser::data::{Declr}, vmrt::Data, builtin::BuiltinFun}; + +pub fn int_to_rat(args: &[Data]) -> Result, ()> { + match args [0] { + Data::Int(val) => Ok(Some(Data::Rat(val as f64))), + _ => Err(()) + } +} + +pub fn rat_to_int(args: &[Data]) -> Result, ()> { + match args[0] { + Data::Rat(val) => Ok(Some(Data::Int(val as i64))), + _ => Err(()) + } +} + +pub fn str_to_int(args: &[Data]) -> Result, ()> { + match &args[0] { + Data::Str(val) => Ok(Some(Data::Int(val.parse().unwrap_or(0)))), + _ => Err(()) + } +} + +pub fn str_to_rat(args: &[Data]) -> Result, ()> { + match &args[0] { + Data::Str(val) => Ok(Some(Data::Rat(val.parse().unwrap_or(0.0)))), + _ => Err(()) + } +} + +pub fn get_module_funs<'a>() -> Vec { + vec![ + BuiltinFun { + declr: Declr::generate_builtin("to_rat", vec![("x", Prim::Int)], Some(Prim::Rat)), + func: &int_to_rat + }, + BuiltinFun { + declr: Declr::generate_builtin("to_int", vec![("x", Prim::Rat)], Some(Prim::Int)), + func: &rat_to_int + }, + BuiltinFun { + declr: Declr::generate_builtin("parse_int", vec![("text", Prim::Str)], Some(Prim::Int)), + func: &str_to_int + }, + BuiltinFun { + declr: Declr::generate_builtin("parse_rat", vec![("text", Prim::Str)], Some(Prim::Rat)), + func: &str_to_rat + } + ] +} \ No newline at end of file diff --git a/src/builtin/modules/io.rs b/src/builtin/modules/io.rs new file mode 100644 index 0000000..58922bf --- /dev/null +++ b/src/builtin/modules/io.rs @@ -0,0 +1,26 @@ +use crate::{token::Prim, parser::data::{Declr}, vmrt::Data, builtin::BuiltinFun}; + +pub fn print(args: &[Data]) -> Result, ()> { + let text = args[0].to_str()?; + print!("{}", text); + Ok(None) +} + +pub fn println(args: &[Data]) -> Result, ()> { + let text = args[0].to_str()?; + println!("{}", text); + Ok(None) +} + +pub fn get_module_funs<'a>() -> Vec { + vec![ + BuiltinFun { + declr: Declr::generate_builtin("print", vec![("text", Prim::Str)], None), + func: &print + }, + BuiltinFun { + declr: Declr::generate_builtin("println", vec![("text", Prim::Str)], None), + func: &println + }, + ] +} \ No newline at end of file diff --git a/src/builtin/modules/math.rs b/src/builtin/modules/math.rs new file mode 100644 index 0000000..dc2cbae --- /dev/null +++ b/src/builtin/modules/math.rs @@ -0,0 +1,57 @@ +use crate::{token::Prim, parser::data::{Declr}, vmrt::Data, builtin::BuiltinFun}; + +pub fn cos(args: &[Data]) -> Result, ()> { + Ok(Some(Data::Rat(args[0].to_float()?.cos()))) +} + +pub fn sin(args: &[Data]) -> Result, ()> { + Ok(Some(Data::Rat(args[0].to_float()?.sin()))) +} + +pub fn tan(args: &[Data]) -> Result, ()> { + Ok(Some(Data::Rat(args[0].to_float()?.tan()))) +} + +pub fn ln(args: &[Data]) -> Result, ()> { + Ok(Some(Data::Rat(args[0].to_float()?.ln()))) +} + +pub fn sqrt(args: &[Data]) -> Result, ()> { + Ok(Some(Data::Rat(args[0].to_float()?.sqrt()))) +} + +pub fn pow(args: &[Data]) -> Result, ()> { + let x = args[0].to_float()?; + let y = args[1].to_float()?; + + Ok(Some(Data::Rat(y.powf(x)))) +} + +pub fn get_module_funs<'a>() -> Vec { + vec![ + BuiltinFun { + declr: Declr::generate_builtin("cos", vec![("x", Prim::Int)], Some(Prim::Rat)), + func: &cos + }, + BuiltinFun { + declr: Declr::generate_builtin("pow", vec![("x", Prim::Rat), ("y", Prim::Rat)], Some(Prim::Rat)), + func: &pow + }, + BuiltinFun { + declr: Declr::generate_builtin("sin", vec![("x", Prim::Int)], Some(Prim::Rat)), + func: &sin + }, + BuiltinFun { + declr: Declr::generate_builtin("tan", vec![("x", Prim::Int)], Some(Prim::Rat)), + func: &tan + }, + BuiltinFun { + declr: Declr::generate_builtin("ln", vec![("x", Prim::Int)], Some(Prim::Rat)), + func: &ln + }, + BuiltinFun { + declr: Declr::generate_builtin("sqrt", vec![("x", Prim::Int)], Some(Prim::Rat)), + func: &sqrt + }, + ] +} \ No newline at end of file diff --git a/src/builtin/modules/mod.rs b/src/builtin/modules/mod.rs new file mode 100644 index 0000000..4611da3 --- /dev/null +++ b/src/builtin/modules/mod.rs @@ -0,0 +1,47 @@ + +pub mod conv; +pub mod math; +pub mod io; +pub mod os; + +#[derive(PartialEq, Eq)] +pub enum Module { + Conv, + Math, + IO, + OS, +} + +impl Module { + + pub fn from_list(text: &str) -> Vec { + let mut vec = vec![]; + + for word in text.split(',') { + match word.trim() { + "conv" => vec.push(Module::Conv), + "math" => vec.push(Module::Math), + "io" => vec.push(Module::IO), + "os" => vec.push(Module::OS), + _ => crate::message(crate::token::MessageType::Warning, format!("unknown module: `{}`", word)) + } + } + + vec + } +} + +pub fn get_submodules<'a>(modules: &[Module]) -> Vec { + let mut funs = vec![]; + + for module in modules { + match module { + Module::Conv => funs.append(&mut conv::get_module_funs()), + Module::Math => funs.append(&mut math::get_module_funs()), + Module::IO => funs.append(&mut io::get_module_funs()), + Module::OS => funs.append(&mut os::get_module_funs()), + } + } + + funs +} \ No newline at end of file diff --git a/src/builtin/modules/os.rs b/src/builtin/modules/os.rs new file mode 100644 index 0000000..0086fe9 --- /dev/null +++ b/src/builtin/modules/os.rs @@ -0,0 +1,21 @@ +use crate::{token::Prim, parser::data::{Declr}, vmrt::Data, builtin::BuiltinFun}; + +pub fn get_os(_: &[Data]) -> Result, ()> { + + if cfg!(windows) { + return Ok(Some(Data::Str(String::from("Windows")))) + } else if cfg!(unix) { + return Ok(Some(Data::Str(String::from("UNIX")))) + } + + Ok(None) +} + +pub fn get_module_funs<'a>() -> Vec { + vec![ + BuiltinFun { + declr: Declr::generate_builtin("get_os", vec![], Some(Prim::Str)), + func: &get_os + }, + ] +} \ No newline at end of file diff --git a/src/direct/mod.rs b/src/direct/mod.rs new file mode 100644 index 0000000..eb7e371 --- /dev/null +++ b/src/direct/mod.rs @@ -0,0 +1,106 @@ +use std::{collections::VecDeque}; + +use crate::{token::{Token}, builtin::modules::Module}; + +#[derive(Default)] +pub struct LangSpecs { + /// builtin modules for extra builtin functions + builtin_features: Vec, + lang_version: u32, + authors: Vec, + embedded_files: Vec, +} + +impl LangSpecs { + + pub fn features(&self) -> &[crate::builtin::modules::Module] { + &self.builtin_features + } +} + +pub fn resolve_directives(tokens: &mut VecDeque) -> LangSpecs { + let mut specs = LangSpecs::default(); + + for token in tokens.iter() { + match token { + Token::CompilerDirective(text, _) => parse_directive(text, &mut specs), + _ => () + } + } + + // remove compiler directives from source + tokens.retain(|token| match token { + Token::CompilerDirective(_, _) => false, + _ => true + }); + + specs +} + +static DIRECTIVE_REGEX_SRC: &'static str = concat!( + r"@feature\(((?:\s*[\w]+\s*,?)*)\)", + r"|@version\(\s*([0-9]{3})\s*\)", + r"|@author\((.*)\)", + r"|@embed\((.*)\)" +); + +lazy_static::lazy_static! { + static ref DIRECTIVE_REGEX: regex::Regex = regex::Regex::new(DIRECTIVE_REGEX_SRC).unwrap(); +} + +pub fn from_list(text: &str) -> Vec { + let mut vec = vec![]; + + for word in text.split(',') { + vec.push(String::from(word.trim())) + } + + vec +} + +fn parse_directive(text: &str, specs: &mut LangSpecs) { + + for cap in DIRECTIVE_REGEX.captures_iter(text) { + let mut enumerator = cap.iter().enumerate(); + loop { + let next = enumerator.next(); + if next.is_none() { + break; + } + + let (i, group) = next.unwrap(); + + // ignore first group as its the entire match, + // as well as the 1st group (= comments) + if i < 1 { + continue; + } + + if let Some(mat) = group { + match i { + 1 => { + specs.builtin_features.append(&mut Module::from_list(mat.as_str())); + return; + }, + 2 => { + specs.lang_version = mat.as_str().parse().unwrap(); + return; + }, + 3 => { + specs.authors.push(String::from(mat.as_str())); + return; + }, + 4 => { + specs.embedded_files.append(&mut from_list(mat.as_str())); + crate::message(crate::token::MessageType::Warning, "Embed directive not working at current state"); + return; + }, + _ => crate::message(crate::token::MessageType::Warning, format!("unknown directive: `{}`", text)), + } + break; + } + } + } + + crate::message(crate::token::MessageType::Warning, format!("unknown directive: `{}`", text)); +} \ No newline at end of file diff --git a/src/seni/mod.rs b/src/seni/mod.rs new file mode 100644 index 0000000..81a75f1 --- /dev/null +++ b/src/seni/mod.rs @@ -0,0 +1,2 @@ +/// SENI - Standard Edition Native Interface (for rust) + diff --git a/src/srcio/mod.rs b/src/srcio/mod.rs new file mode 100644 index 0000000..d06d91b --- /dev/null +++ b/src/srcio/mod.rs @@ -0,0 +1,31 @@ +use std::{fs}; + +pub struct CodeSrc { + _path: String, + src: String, +} + +impl CodeSrc { + + pub fn new(path: &String) -> Result { + Ok(Self { + _path: path.to_owned(), + src: Self::read_code(path)?, + }) + } + + fn read_code(path: &String) -> Result { + let result = fs::read_to_string(path); + + // read the source + if let Ok(src) = result { + return Ok(src); + } + + Err(format!("unable to fetch source code from {}: {}", path, result.err().unwrap())) + } + + pub fn code(&self) -> &String { + &self.src + } +} \ No newline at end of file diff --git a/test.yard b/test.yard new file mode 100644 index 0000000..82f9984 --- /dev/null +++ b/test.yard @@ -0,0 +1,35 @@ +@feature(io) +@version(100) +@author(Sven Vogel) + +// recursion! +fac(x:int) = int { + despite x != 1 { + yield 1; + } + + yield fac(x - 1) * x +} + +main() = int { + + x = 0 + loop { + + until x > 9 { + despite x != 5 { + x = x + 1 + cont + } + + println(""..x); + x = x + 1 + } + + break + } + + println(""..fract(456.3928)); + + yield 0 +} \ No newline at end of file