diff --git a/axel/Cargo.toml b/axel/Cargo.toml new file mode 100644 index 0000000..1773b2b --- /dev/null +++ b/axel/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "axel" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +versioning = {git = "https://git.ablecorp.us/able/versioning"} +hashbrown = "0.12.0" +log = "0.4.14" + +[dependencies.logos] +version = "0.12.0" +default-features = false +features = ["export_derive"] diff --git a/axel/src/lib.rs b/axel/src/lib.rs new file mode 100644 index 0000000..5ffd08f --- /dev/null +++ b/axel/src/lib.rs @@ -0,0 +1,80 @@ +#![no_std] +#![deny(unsafe_code, missing_docs)] +//! A simple format for apis + +use { + hashbrown::HashMap, + logos::Logos, + node::{lexer::Token, tree::AxelNode}, +}; + +pub(crate) use alloc::{ + string::{String, ToString}, + vec::Vec, +}; +pub use node::signature::FunctionSignature; + +pub extern crate alloc; + +pub mod node; + +/// Parse a string into a vector of nodes +pub fn parse(string: String) -> Vec { + let lex = Token::lexer(&string); + let mut node_list: Vec = Vec::new(); + + let mut node = AxelNode { + name: String::new(), + vals: HashMap::new(), + functs: Vec::new(), + }; + let mut last_type_key = false; + let mut key = String::new(); + + for token in lex { + use Token::*; + match token { + Key(data) => { + key = data; + last_type_key = true; + } + NodeName(name) => { + node.name = name; + } + Version(version) if last_type_key => { + use node::tree::Values::*; + node.vals.insert(key.clone(), Version(version)); + } + True => { + use node::tree::Values::*; + node.vals.insert(key.clone(), Boolean(true)); + } + False => { + use node::tree::Values::*; + node.vals.insert(key.clone(), Boolean(false)); + } + NodeClose => { + node_list.push(node); + node = AxelNode { + name: String::new(), + vals: HashMap::new(), + functs: Vec::new(), + }; + } + Number(number) => { + if last_type_key { + use node::tree::Values::*; + node.vals.insert(key.clone(), Number(number)); + } + } + + FunctionSignature(signature) => { + node.functs.push((key.clone(), signature)); + } + + _ => {} + } + } + + node_list +} diff --git a/axel/src/main.rs b/axel/src/main.rs new file mode 100644 index 0000000..4cc5d2d --- /dev/null +++ b/axel/src/main.rs @@ -0,0 +1,9 @@ +use axel::parse; + +pub fn main() { + let p = parse(include_str!("mouse.axel").to_string()); + + for node in p { + println!("{:?}", node); + } +} diff --git a/axel/src/mouse.axel b/axel/src/mouse.axel new file mode 100644 index 0000000..c0c1fde --- /dev/null +++ b/axel/src/mouse.axel @@ -0,0 +1,11 @@ +mouse{ +val= + x: 1000 + y: 200 + buttons: true +fn| + sub: (Num,Num)->(Num); + floatify: (Num,Num)->(Float); + able: (None)->(None); + foo: (None)->(Num); +} diff --git a/axel/src/node/lexer.rs b/axel/src/node/lexer.rs new file mode 100644 index 0000000..141d974 --- /dev/null +++ b/axel/src/node/lexer.rs @@ -0,0 +1,92 @@ +//! + +use crate::*; + +use super::signature::{signature_handle, FunctionSignature}; +use alloc::string::ToString; +use logos::{Lexer, Logos}; +use versioning::Version; + +#[derive(Logos, Debug, PartialEq)] +/// +pub enum Token { + #[regex("[(][a-zA-Z,]+[)]->[(][a-zA-Z,]+[)]", signature_handle)] + /// + FunctionSignature(FunctionSignature), + + #[token("true")] + /// True + True, + + #[token("false")] + /// False + False, + + #[regex("[a-zA-Z]+=")] + /// + Values, + + #[regex("[a-zA-Z]+|")] + /// + Functions, + + #[regex("[a-zA-Z]+[:]", node_handler)] + /// + Key(String), + + #[regex("[a-zA-Z]+[{]", node_handler)] + /// + NodeName(String), + + #[regex("[a-zA-Z]+[(]", node_handler)] + /// + FunctionName(String), + + #[regex("[0-9].[0-9].[0-9]", version_parse)] + /// + Version(Version), + + #[regex("-?[0-9]+", num_handler)] + + /// + Number(i32), + + #[token("}")] + /// + NodeClose, + + #[error] + #[regex(r"[ \t\n\f]+", logos::skip)] + /// + Error, +} + +fn node_handler(lex: &mut Lexer) -> Option { + let slice = lex.slice(); + let mut node = slice.to_string(); + node.pop(); + Some(node) +} + +fn version_parse(lex: &mut Lexer) -> Option { + let slice = lex.slice(); + let mut version = Version { + major: 0, + minor: 0, + patch: 0, + }; + + let mut parts = slice.split('.'); + version.major = parts.next().unwrap().parse().unwrap(); + version.minor = parts.next().unwrap().parse().unwrap(); + version.patch = parts.next().unwrap().parse().unwrap(); + + Some(version) +} + +fn num_handler(lex: &mut Lexer) -> Option { + let slice = lex.slice(); + let mut num = slice.to_string(); + num.pop(); + Some(num.parse().unwrap()) +} diff --git a/axel/src/node/mod.rs b/axel/src/node/mod.rs new file mode 100644 index 0000000..9cec612 --- /dev/null +++ b/axel/src/node/mod.rs @@ -0,0 +1,5 @@ +//! + +pub mod lexer; +pub mod signature; +pub mod tree; diff --git a/axel/src/node/signature.rs b/axel/src/node/signature.rs new file mode 100644 index 0000000..56dec9e --- /dev/null +++ b/axel/src/node/signature.rs @@ -0,0 +1,52 @@ +//! + +use crate::*; + +use logos::Lexer; + +/// A function signature of an axel node +pub type FunctionSignature = (Vec, Vec); + +use super::{lexer::Token, tree::Values}; + +/// Construct a signature handler +pub fn signature_handle(lex: &mut Lexer) -> Option { + let slice = lex.slice(); + let string_sig = slice.to_string(); + let mut str_pli = string_sig.split("->"); + let intype = str_pli.next().unwrap().to_string(); + let outtype = str_pli.next().unwrap().to_string(); + let ins = typeify(intype); + let outs = typeify(outtype); + + Some((ins, outs)) +} +/// Turn a string into a vector of values +pub fn typeify(mut types: String) -> Vec { + let mut ret = Vec::new(); + + types.remove(0); + types.pop(); + for t in types.split(',') { + match t { + "Num" => { + ret.push(Values::Number(0)); + } + "Float" => { + ret.push(Values::Float(0.0)); + } + "String" => { + ret.push(Values::String("".to_string())); + } + "None" => { + ret.push(Values::Empty); + } + "Bool" => { + ret.push(Values::Boolean(false)); + } + _ => {} + } + } + + ret +} diff --git a/axel/src/node/tree.rs b/axel/src/node/tree.rs new file mode 100644 index 0000000..39a2641 --- /dev/null +++ b/axel/src/node/tree.rs @@ -0,0 +1,43 @@ +//! + +use crate::*; + +#[derive(Debug, PartialEq)] +/// +pub enum Values { + /// No value + Empty, + /// + Version(versioning::Version), + + /// + Number(i32), + /// + Float(f32), + /// + String(String), + /// + Boolean(bool), +} + +#[derive(Debug)] +/// +pub struct AxelNode { + /// + pub name: String, + /// + pub vals: HashMap, + /// + pub functs: Vec<(String, FunctionSignature)>, +} + +impl AxelNode { + /// Generate an empty axel node + pub fn new(name: String) -> Self { + AxelNode { + name, + vals: HashMap::new(), + functs: Vec::new(), + } + } +} diff --git a/versioning/Cargo.toml b/versioning/Cargo.toml new file mode 100644 index 0000000..db6380d --- /dev/null +++ b/versioning/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "versioning" +version = "0.1.2" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +[dependencies.serde] +version = "1.0" +features = ["derive"] \ No newline at end of file diff --git a/versioning/src/lib.rs b/versioning/src/lib.rs new file mode 100644 index 0000000..f59d7fd --- /dev/null +++ b/versioning/src/lib.rs @@ -0,0 +1,13 @@ +// ! A unified versioning system for Rust. +#![no_std] + +use core::prelude::rust_2021::derive; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +pub struct Version { + pub major: u8, + pub minor: u8, + pub patch: u8, +}