latest pushes

This commit is contained in:
Ronaldson Bellande 2024-10-07 11:15:35 -04:00
parent 4426007efa
commit 62363b8b23
28 changed files with 2675 additions and 1 deletions

22
.github/workflows/rust.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: Rust
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
publish.sh
Cargo.lock
target
scripts

64
Cargo.toml Normal file
View File

@ -0,0 +1,64 @@
[package]
name = "bellronos"
version = "0.0.1"
edition = "2021"
authors = ["Ronaldson Bellande <ronaldsonbellande@gmail.com>"]
description = "Bellande Operating System Programming Language written in Rust"
license = "GPL-3.0-or-later"
repository = "https://github.com/Architecture-Mechanism/bellronos"
documentation = "https://bellande-architecture-mechanism-research-innovation-center.org/bellronos/docs"
readme = "README.md"
keywords = ["programming-language", "operating-system", "bellronos"]
categories = ["compilers", "development-tools"]
[lib]
name = "bellronos"
path = "src/bellronos.rs"
[dependencies]
glob = "0.3.1"
tempfile = "3.3.0"
shellexpand = "3.1.0"
meval = "0.2.0"
reqwest = { version = "0.11", features = ["json", "blocking"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
anyhow = "1.0"
clap = { version = "4.0", features = ["derive"] }
regex = "1.7"
lazy_static = "1.4"
log = "0.4"
env_logger = "0.10"
tokio = { version = "1.0", features = ["full"] }
async-trait = "0.1"
futures = "0.3"
chrono = "0.4"
rand = "0.8"
[dev-dependencies]
assert_cmd = "2.0"
predicates = "3.0"
criterion = "0.4"
[profile.release]
lto = true
codegen-units = 1
panic = "abort"
opt-level = 3
debug = false
debug-assertions = false
overflow-checks = false
incremental = false
[features]
default = ["std"]
std = []
nightly = ["compiler_builtins", "core", "alloc"]
compiler_builtins = []
core = []
alloc = []
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

View File

@ -3,8 +3,24 @@
## Bellande Operating System Programming Language written in Rust
- Can be used in any Operating System but Bellande Operating System works optimally when you use Bellronos Programming Language
## BELLRONOS Usage
## Website Crates
- https://crates.io/crates/bellronos
### Installation
- `cargo add bellronos`
```
Name: bellronos
Version: 0.0.1
Summary: Bellande Operating System Scripting Language
Home-page: github.com/Architecture-Mechanism/bellronos
Author: Ronaldson Bellande
Author-email: ronaldsonbellande@gmail.com
License: GNU General Public License v3.0
```
## License
bellronos BellandeOS Programming Language is distributed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html), see [LICENSE](https://github.com/Architecture-Mechanism/bellronos/blob/main/LICENSE) and [NOTICE](https://github.com/Architecture-Mechanism/bellronos/blob/main/LICENSE) for more information.
Bellronos BellandeOS Programming Language is distributed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html), see [LICENSE](https://github.com/Architecture-Mechanism/bellronos/blob/main/LICENSE) and [NOTICE](https://github.com/Architecture-Mechanism/bellronos/blob/main/LICENSE) for more information.

View File

@ -0,0 +1,100 @@
# example.bellronos
import math
import io
import string
define calculate_circle_area(radius: float) -> float:
return math.pi * radius * radius
define greet(name: string) -> none:
io.print("Hello, " + string.to_upper(name) + "!")
class Person:
define __init__(self, name: string, age: int) -> none:
self.name = name
self.age = age
define introduce(self) -> none:
io.print("My name is " + self.name + " and I'm " + string.to_string(self.age) + " years old.")
define main() -> none:
# Basic operations and function calls
set radius to 5.0
set area to calculate_circle_area(radius)
io.print("The area of a circle with radius " + string.to_string(radius) + " is " + string.to_string(area))
greet("Bellronos")
# Class usage
set person to Person("Alice", 30)
person.introduce()
# Closures
set multiplier to closure (x: int) -> int: return x * 2
io.print("Doubled 5: " + string.to_string(multiplier(5)))
# Generators
define count_to(n: int) -> generator:
set i to 0
while i < n:
yield i
set i to i + 1
for num in count_to(5):
io.print("Generated number: " + string.to_string(num))
# Async/await (simulated)
async define fetch_data() -> string:
# Simulating an asynchronous operation
io.print("Fetching data...")
return "Data fetched successfully"
async define process_data() -> none:
set result to await fetch_data()
io.print("Processing result: " + result)
process_data()
# Language interoperability
set c_code to "
#include <stdio.h>
int main() {
printf(\"Hello from C!\\n\");
return 0;
}
"
io.print(execute_c(c_code))
set python_code to "
print('Hello from Python!')
"
io.print(execute_python(python_code))
set js_code to "
console.log('Hello from JavaScript!');
"
io.print(execute_javascript(js_code))
set java_code to "
public class Temp {
public static void main(String[] args) {
System.out.println(\"Hello from Java!\");
}
}
"
io.print(execute_java(java_code))
set rust_code to "
fn main() {
println!(\"Hello from Rust!\");
}
"
io.print(execute_rust(rust_code))
set swift_code to "
print(\"Hello from Swift!\")
"
io.print(execute_swift(swift_code))
main()

22
dependencies.txt Normal file
View File

@ -0,0 +1,22 @@
glob = "0.3.1"
tempfile = "3.3.0"
shellexpand = "3.1.0"
meval = "0.2.0"
reqwest = { version = "0.11", features = ["json", "blocking"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
anyhow = "1.0"
clap = { version = "4.0", features = ["derive"] }
regex = "1.7"
lazy_static = "1.4"
log = "0.4"
env_logger = "0.10"
tokio = { version = "1.0", features = ["full"] }
async-trait = "0.1"
futures = "0.3"
chrono = "0.4"
rand = "0.8"
assert_cmd = "2.0"
predicates = "3.0"
criterion = "0.4"

3
git_scripts/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
fix_errors.sh
push.sh
repository_recal.sh

1
make_rust_executable.bellos Executable file
View File

@ -0,0 +1 @@
bellande_rust_executable -d dependencies.txt -s src -m bellronos.rs -o executable/bellronos

1
make_rust_executable.sh Executable file
View File

@ -0,0 +1 @@
bellande_rust_executable -d dependencies.txt -s src -m bellronos.rs -o executable/bellronos

111
src/ast/ast.rs Normal file
View File

@ -0,0 +1,111 @@
// Copyright (C) 2024 Bellande Architecture Mechanism Research Innovation Center, Ronaldson Bellande
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::type_system::type_system::Type;
#[derive(Clone, PartialEq, Debug)]
pub enum ASTNode {
Module {
body: Vec<ASTNode>,
},
Import {
names: Vec<String>,
},
FunctionDef {
name: String,
args: Vec<(String, Type)>,
return_type: Type,
body: Vec<ASTNode>,
},
ClassDef {
name: String,
methods: Vec<ASTNode>,
},
Assign {
target: String,
value: Box<ASTNode>,
},
Expr {
value: Box<ASTNode>,
},
Call {
func: String,
args: Vec<ASTNode>,
},
Str {
value: String,
},
Num {
value: f64,
},
Bool {
value: bool,
},
Name {
id: String,
},
BinOp {
left: Box<ASTNode>,
op: String,
right: Box<ASTNode>,
},
If {
condition: Box<ASTNode>,
body: Vec<ASTNode>,
orelse: Vec<ASTNode>,
},
While {
condition: Box<ASTNode>,
body: Vec<ASTNode>,
},
For {
target: String,
iter: Box<ASTNode>,
body: Vec<ASTNode>,
},
Return {
value: Option<Box<ASTNode>>,
},
Closure {
params: Vec<(String, Type)>,
body: Box<ASTNode>,
},
Generator {
body: Vec<ASTNode>,
},
Yield {
value: Box<ASTNode>,
},
Async {
body: Vec<ASTNode>,
},
Await {
value: Box<ASTNode>,
},
List {
elements: Vec<ASTNode>,
},
Dict {
pairs: Vec<(ASTNode, ASTNode)>,
},
Attribute {
value: Box<ASTNode>,
attr: String,
},
InteropCall {
language: String,
code: String,
},
}

1
src/ast/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod ast;

53
src/bellronos.rs Normal file
View File

@ -0,0 +1,53 @@
// Copyright (C) 2024 Bellande Architecture Mechanism Research Innovation Center, Ronaldson Bellande
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
mod ast;
mod error;
mod interop;
mod interpreter;
mod lexer;
mod package_manager;
mod parser;
mod standard_library;
mod type_system;
use error::error::BellronosError;
use interpreter::interpreter::BellronosInterpreter;
use package_manager::package_manager::PackageManager;
use std::env;
use std::fs;
fn main() -> Result<(), BellronosError> {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
println!("Usage: bellronos <filename> [--install <package>]");
return Ok(());
}
if args[1] == "--install" && args.len() == 3 {
let package_manager = PackageManager::new("packages".to_string());
package_manager.install_package(&args[2])?;
println!("Package {} installed successfully", args[2]);
return Ok(());
}
let filename = &args[1];
let contents = fs::read_to_string(filename)?;
let mut interpreter = BellronosInterpreter::new();
interpreter.run(&contents, filename)?;
Ok(())
}

49
src/error/error.rs Normal file
View File

@ -0,0 +1,49 @@
// Copyright (C) 2024 Bellande Architecture Mechanism Research Innovation Center, Ronaldson Bellande
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use std::error::Error;
use std::fmt;
use std::io;
#[derive(Debug)]
pub enum BellronosError {
IO(io::Error),
Parser(String),
Type(String),
Runtime(String),
Network(String),
Package(String),
}
impl fmt::Display for BellronosError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BellronosError::IO(err) => write!(f, "IO error: {}", err),
BellronosError::Parser(msg) => write!(f, "Parser error: {}", msg),
BellronosError::Type(msg) => write!(f, "Type error: {}", msg),
BellronosError::Runtime(msg) => write!(f, "Runtime error: {}", msg),
BellronosError::Network(msg) => write!(f, "Network error: {}", msg),
BellronosError::Package(msg) => write!(f, "Package error: {}", msg),
}
}
}
impl Error for BellronosError {}
impl From<io::Error> for BellronosError {
fn from(err: io::Error) -> BellronosError {
BellronosError::IO(err)
}
}

1
src/error/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod error;

147
src/interop/interop.rs Normal file
View File

@ -0,0 +1,147 @@
// Copyright (C) 2024 Bellande Architecture Mechanism Research Innovation Center, Ronaldson Bellande
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error::error::BellronosError;
use crate::interpreter::interpreter::Value;
use std::process::Command;
pub struct LanguageInterop;
impl LanguageInterop {
pub fn new() -> Self {
LanguageInterop
}
pub fn execute(&self, language: &str, code: &str) -> Result<Value, BellronosError> {
match language {
"c" => self.execute_c(code),
"python" => self.execute_python(code),
"javascript" => self.execute_javascript(code),
"java" => self.execute_java(code),
"rust" => self.execute_rust(code),
"swift" => self.execute_swift(code),
_ => Err(BellronosError::Runtime(format!(
"Unsupported language: {}",
language
))),
}
}
fn execute_c(&self, code: &str) -> Result<Value, BellronosError> {
let temp_file = "temp.c";
std::fs::write(temp_file, code)?;
let output = Command::new("gcc")
.args(&[temp_file, "-o", "temp_c"])
.output()?;
if !output.status.success() {
return Err(BellronosError::Runtime(format!(
"C compilation error: {}",
String::from_utf8_lossy(&output.stderr)
)));
}
let output = Command::new("./temp_c").output()?;
std::fs::remove_file(temp_file)?;
std::fs::remove_file("temp_c")?;
Ok(Value::String(
String::from_utf8_lossy(&output.stdout).to_string(),
))
}
fn execute_python(&self, code: &str) -> Result<Value, BellronosError> {
let output = Command::new("python").arg("-c").arg(code).output()?;
Ok(Value::String(
String::from_utf8_lossy(&output.stdout).to_string(),
))
}
fn execute_javascript(&self, code: &str) -> Result<Value, BellronosError> {
let output = Command::new("node").arg("-e").arg(code).output()?;
Ok(Value::String(
String::from_utf8_lossy(&output.stdout).to_string(),
))
}
fn execute_java(&self, code: &str) -> Result<Value, BellronosError> {
let temp_file = "Temp.java";
std::fs::write(temp_file, code)?;
let output = Command::new("javac").arg(temp_file).output()?;
if !output.status.success() {
return Err(BellronosError::Runtime(format!(
"Java compilation error: {}",
String::from_utf8_lossy(&output.stderr)
)));
}
let output = Command::new("java").arg("Temp").output()?;
std::fs::remove_file(temp_file)?;
std::fs::remove_file("Temp.class")?;
Ok(Value::String(
String::from_utf8_lossy(&output.stdout).to_string(),
))
}
fn execute_rust(&self, code: &str) -> Result<Value, BellronosError> {
let temp_file = "temp.rs";
std::fs::write(temp_file, code)?;
let output = Command::new("rustc").arg(temp_file).output()?;
if !output.status.success() {
return Err(BellronosError::Runtime(format!(
"Rust compilation error: {}",
String::from_utf8_lossy(&output.stderr)
)));
}
let output = Command::new("./temp").output()?;
std::fs::remove_file(temp_file)?;
std::fs::remove_file("temp")?;
Ok(Value::String(
String::from_utf8_lossy(&output.stdout).to_string(),
))
}
fn execute_swift(&self, code: &str) -> Result<Value, BellronosError> {
let temp_file = "temp.swift";
std::fs::write(temp_file, code)?;
let output = Command::new("swift").arg(temp_file).output()?;
std::fs::remove_file(temp_file)?;
if output.status.success() {
Ok(Value::String(
String::from_utf8_lossy(&output.stdout).to_string(),
))
} else {
Err(BellronosError::Runtime(format!(
"Swift execution error: {}",
String::from_utf8_lossy(&output.stderr)
)))
}
}
}

1
src/interop/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod interop;

View File

@ -0,0 +1,450 @@
// Copyright (C) 2024 Bellande Architecture Mechanism Research Innovation Center, Ronaldson Bellande
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::ast::ast::ASTNode;
use crate::error::error::BellronosError;
use crate::interop::interop::LanguageInterop;
use crate::lexer::lexer::Lexer;
use crate::package_manager::package_manager::PackageManager;
use crate::parser::parser::Parser;
use crate::standard_library::standard_library::StandardLibrary;
use crate::type_system::type_system::TypeChecker;
use std::cell::RefCell;
use std::collections::HashMap;
use std::f64;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
type Environment = Rc<RefCell<HashMap<String, Value>>>;
#[derive(Clone)]
pub enum Value {
Int(i64),
Float(f64),
String(String),
Bool(bool),
List(Vec<Value>),
Dict(HashMap<String, Value>),
Function(Vec<String>, Vec<ASTNode>, Environment),
Class {
methods: HashMap<String, Value>,
},
Instance {
class: String,
attributes: HashMap<String, Value>,
},
Closure(Vec<String>, Vec<ASTNode>, Environment),
Generator(Vec<ASTNode>, Environment, usize),
None,
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Value::Int(a), Value::Int(b)) => a == b,
(Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
(Value::String(a), Value::String(b)) => a == b,
(Value::Bool(a), Value::Bool(b)) => a == b,
(Value::List(a), Value::List(b)) => a == b,
(Value::Dict(a), Value::Dict(b)) => a == b,
// For Function, Class, Instance, Closure, and Generator, compare memory addresses
(Value::Function(_, _, _), Value::Function(_, _, _)) => std::ptr::eq(self, other),
(Value::Class { .. }, Value::Class { .. }) => std::ptr::eq(self, other),
(Value::Instance { .. }, Value::Instance { .. }) => std::ptr::eq(self, other),
(Value::Closure(_, _, _), Value::Closure(_, _, _)) => std::ptr::eq(self, other),
(Value::Generator(_, _, _), Value::Generator(_, _, _)) => std::ptr::eq(self, other),
(Value::None, Value::None) => true,
_ => false,
}
}
}
impl Eq for Value {}
impl Hash for Value {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
Value::Int(i) => i.hash(state),
Value::Float(f) => f.to_bits().hash(state),
Value::String(s) => s.hash(state),
Value::Bool(b) => b.hash(state),
Value::List(l) => l.hash(state),
Value::Dict(d) => {
for (k, v) in d {
k.hash(state);
v.hash(state);
}
}
// For Function, Class, Instance, Closure, and Generator, hash memory addresses
Value::Function(_, _, _)
| Value::Class { .. }
| Value::Instance { .. }
| Value::Closure(_, _, _)
| Value::Generator(_, _, _) => (self as *const Value).hash(state),
Value::None => 0.hash(state),
}
}
}
pub struct BellronosInterpreter {
global_env: Environment,
type_checker: TypeChecker,
stdlib: StandardLibrary,
package_manager: PackageManager,
language_interop: LanguageInterop,
}
impl BellronosInterpreter {
pub fn new() -> Self {
let global_env = Rc::new(RefCell::new(HashMap::new()));
let type_checker = TypeChecker::new();
let stdlib = StandardLibrary::new();
let package_manager = PackageManager::new("packages".to_string());
let language_interop = LanguageInterop::new();
BellronosInterpreter {
global_env,
type_checker,
stdlib,
package_manager,
language_interop,
}
}
pub fn run(&mut self, code: &str, _filename: &str) -> Result<(), BellronosError> {
let mut lexer = Lexer::new(code);
let tokens = lexer.tokenize()?;
let mut parser = Parser::new(tokens);
let ast = parser.parse()?;
self.interpret(&ast)?;
Ok(())
}
fn interpret(&mut self, node: &ASTNode) -> Result<Value, BellronosError> {
match node {
ASTNode::Module { body } => {
let mut result = Value::None;
for stmt in body {
result = self.interpret(stmt)?;
}
Ok(result)
}
ASTNode::Import { names } => {
for name in names {
if let Some(module) = self.stdlib.get_module(name) {
self.global_env
.borrow_mut()
.insert(name.clone(), Value::Dict(module.clone()));
} else {
let package_code = self.package_manager.load_package(name)?;
self.run(&package_code, name)?;
}
}
Ok(Value::None)
}
ASTNode::FunctionDef {
name,
args,
return_type: _,
body,
} => {
let func = Value::Function(
args.iter().map(|(name, _)| name.clone()).collect(),
body.clone(),
Rc::clone(&self.global_env),
);
self.global_env.borrow_mut().insert(name.clone(), func);
Ok(Value::None)
}
ASTNode::ClassDef { name, methods } => {
let mut class_methods = HashMap::new();
for method in methods {
if let ASTNode::FunctionDef {
name: method_name,
args,
return_type: _,
body,
} = method
{
let method_func = Value::Function(
args.iter().map(|(name, _)| name.clone()).collect(),
body.clone(),
Rc::clone(&self.global_env),
);
class_methods.insert(method_name.clone(), method_func);
}
}
let class = Value::Class {
methods: class_methods,
};
self.global_env.borrow_mut().insert(name.clone(), class);
Ok(Value::None)
}
ASTNode::Assign { target, value } => {
let val = self.interpret(value)?;
self.global_env.borrow_mut().insert(target.clone(), val);
Ok(Value::None)
}
ASTNode::Expr { value } => self.interpret(value),
ASTNode::Call { func, args } => {
let f = self.global_env.borrow().get(func).cloned().ok_or_else(|| {
BellronosError::Runtime(format!("Undefined function: {}", func))
})?;
match f {
Value::Function(params, body, env) => {
let mut local_env = env.borrow().clone();
for (param, arg) in params.iter().zip(args) {
local_env.insert(param.clone(), self.interpret(arg)?);
}
let local_env = Rc::new(RefCell::new(local_env));
let mut result = Value::None;
for stmt in &body {
result = self.interpret_with_env(stmt, &local_env)?;
}
Ok(result)
}
Value::Class { methods: _ } => {
let instance = Value::Instance {
class: func.clone(),
attributes: HashMap::new(),
};
Ok(instance)
}
_ => Err(BellronosError::Runtime(format!("{} is not callable", func))),
}
}
ASTNode::Str { value } => Ok(Value::String(value.clone())),
ASTNode::Num { value } => Ok(Value::Float(*value)),
ASTNode::Bool { value } => Ok(Value::Bool(*value)),
ASTNode::Name { id } => self
.global_env
.borrow()
.get(id)
.cloned()
.ok_or_else(|| BellronosError::Runtime(format!("Undefined variable: {}", id))),
ASTNode::BinOp { left, op, right } => {
let left_val = self.interpret(left)?;
let right_val = self.interpret(right)?;
match (left_val, op.as_str(), right_val) {
(Value::Int(l), "+", Value::Int(r)) => Ok(Value::Int(l + r)),
(Value::Float(l), "+", Value::Float(r)) => Ok(Value::Float(l + r)),
(Value::String(l), "+", Value::String(r)) => Ok(Value::String(l + &r)),
(Value::Int(l), "-", Value::Int(r)) => Ok(Value::Int(l - r)),
(Value::Float(l), "-", Value::Float(r)) => Ok(Value::Float(l - r)),
(Value::Int(l), "*", Value::Int(r)) => Ok(Value::Int(l * r)),
(Value::Float(l), "*", Value::Float(r)) => Ok(Value::Float(l * r)),
(Value::Int(l), "/", Value::Int(r)) => Ok(Value::Float(l as f64 / r as f64)),
(Value::Float(l), "/", Value::Float(r)) => Ok(Value::Float(l / r)),
(Value::Int(l), ">", Value::Int(r)) => Ok(Value::Bool(l > r)),
(Value::Float(l), ">", Value::Float(r)) => Ok(Value::Bool(l > r)),
(Value::Int(l), "<", Value::Int(r)) => Ok(Value::Bool(l < r)),
(Value::Float(l), "<", Value::Float(r)) => Ok(Value::Bool(l < r)),
(Value::Int(l), ">=", Value::Int(r)) => Ok(Value::Bool(l >= r)),
(Value::Float(l), ">=", Value::Float(r)) => Ok(Value::Bool(l >= r)),
(Value::Int(l), "<=", Value::Int(r)) => Ok(Value::Bool(l <= r)),
(Value::Float(l), "<=", Value::Float(r)) => Ok(Value::Bool(l <= r)),
(Value::Int(l), "==", Value::Int(r)) => Ok(Value::Bool(l == r)),
(Value::Float(l), "==", Value::Float(r)) => Ok(Value::Bool(l == r)),
(Value::String(l), "==", Value::String(r)) => Ok(Value::Bool(l == r)),
(Value::Bool(l), "==", Value::Bool(r)) => Ok(Value::Bool(l == r)),
_ => Err(BellronosError::Runtime(format!(
"Unsupported operation: {:?} {} {:?}",
left, op, right
))),
}
}
ASTNode::If {
condition,
body,
orelse,
} => {
let cond_value = self.interpret(condition)?;
if let Value::Bool(true) = cond_value {
for stmt in body {
self.interpret(stmt)?;
}
} else {
for stmt in orelse {
self.interpret(stmt)?;
}
}
Ok(Value::None)
}
ASTNode::While { condition, body } => {
loop {
let cond_value = self.interpret(condition)?;
if let Value::Bool(true) = cond_value {
for stmt in body {
self.interpret(stmt)?;
}
} else {
break;
}
}
Ok(Value::None)
}
ASTNode::For { target, iter, body } => {
let iter_value = self.interpret(iter)?;
if let Value::List(items) = iter_value {
for item in items {
self.global_env.borrow_mut().insert(target.clone(), item);
for stmt in body {
self.interpret(stmt)?;
}
}
} else {
return Err(BellronosError::Runtime(
"For loop iterable must be a list".to_string(),
));
}
Ok(Value::None)
}
ASTNode::Return { value } => {
if let Some(v) = value {
self.interpret(v)
} else {
Ok(Value::None)
}
}
ASTNode::Closure { params, body } => Ok(Value::Closure(
params.iter().map(|(name, _)| name.clone()).collect(),
vec![*body.clone()],
Rc::clone(&self.global_env),
)),
ASTNode::Generator { body } => Ok(Value::Generator(
body.clone(),
Rc::clone(&self.global_env),
0,
)),
ASTNode::Yield { value: _ } => Err(BellronosError::Runtime(
"Yield outside of generator".to_string(),
)),
ASTNode::Async { body } => {
let mut result = Value::None;
for stmt in body {
result = self.interpret(stmt)?;
}
Ok(result)
}
ASTNode::Await { value } => self.interpret(value),
ASTNode::List { elements } => {
let mut list = Vec::new();
for elem in elements {
list.push(self.interpret(elem)?);
}
Ok(Value::List(list))
}
ASTNode::Dict { pairs } => {
let mut dict = HashMap::new();
for (key, value) in pairs {
if let Value::String(k) = self.interpret(key)? {
let v = self.interpret(value)?;
dict.insert(k, v);
} else {
return Err(BellronosError::Runtime(
"Dictionary keys must be strings".to_string(),
));
}
}
Ok(Value::Dict(dict))
}
ASTNode::Attribute { value, attr } => {
let obj = self.interpret(value)?;
match obj {
Value::Instance { class, attributes } => {
if let Some(attr_value) = attributes.get(attr) {
Ok(attr_value.clone())
} else if let Some(Value::Class { methods }) =
self.global_env.borrow().get(&class)
{
if let Some(method) = methods.get(attr) {
Ok(method.clone())
} else {
Err(BellronosError::Runtime(format!(
"Attribute '{}' not found on instance of class '{}'",
attr, class
)))
}
} else {
Err(BellronosError::Runtime(format!(
"Class '{}' not found",
class
)))
}
}
_ => Err(BellronosError::Runtime(format!(
"Cannot access attribute '{}' on non-instance type",
attr
))),
}
}
ASTNode::InteropCall { language, code } => {
self.language_interop.execute(language, code)
}
}
}
fn interpret_with_env(
&mut self,
node: &ASTNode,
env: &Environment,
) -> Result<Value, BellronosError> {
let old_env = self.global_env.clone();
*self.global_env.borrow_mut() = env.borrow().clone();
let result = self.interpret(node);
*self.global_env.borrow_mut() = old_env.borrow().clone();
result
}
}
impl std::fmt::Debug for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::Int(i) => write!(f, "{}", i),
Value::Float(fl) => write!(f, "{}", fl),
Value::String(s) => write!(f, "\"{}\"", s),
Value::Bool(b) => write!(f, "{}", b),
Value::List(l) => {
write!(f, "[")?;
for (i, item) in l.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{:?}", item)?;
}
write!(f, "]")
}
Value::Dict(d) => {
write!(f, "{{")?;
for (i, (k, v)) in d.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "\"{}\": {:?}", k, v)?;
}
write!(f, "}}")
}
Value::Function(_, _, _) => write!(f, "<function>"),
Value::Class { .. } => write!(f, "<class>"),
Value::Instance { class, .. } => write!(f, "<instance of {}>", class),
Value::Closure(_, _, _) => write!(f, "<closure>"),
Value::Generator(_, _, _) => write!(f, "<generator>"),
Value::None => write!(f, "None"),
}
}
}

1
src/interpreter/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod interpreter;

308
src/lexer/lexer.rs Normal file
View File

@ -0,0 +1,308 @@
// Copyright (C) 2024 Bellande Architecture Mechanism Research Innovation Center, Ronaldson Bellande
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error::error::BellronosError;
#[derive(Debug, Clone, PartialEq)]
pub enum Token {
Import,
Define,
Class,
Set,
To,
If,
Else,
While,
For,
In,
Return,
Async,
Await,
Yield,
Closure,
True,
False,
Identifier(String),
String(String),
Number(f64),
LeftParen,
RightParen,
LeftBrace,
RightBrace,
LeftBracket,
RightBracket,
Colon,
Comma,
Dot,
Plus,
Minus,
Multiply,
Divide,
Equals,
NotEquals,
LessThan,
GreaterThan,
LessThanOrEqual,
GreaterThanOrEqual,
Arrow,
Newline,
EOF,
}
pub struct Lexer {
input: Vec<char>,
position: usize,
line: usize,
column: usize,
}
impl Lexer {
pub fn new(input: &str) -> Self {
Lexer {
input: input.chars().collect(),
position: 0,
line: 1,
column: 1,
}
}
pub fn tokenize(&mut self) -> Result<Vec<Token>, BellronosError> {
let mut tokens = Vec::new();
while let Some(token) = self.next_token()? {
tokens.push(token);
}
tokens.push(Token::EOF);
Ok(tokens)
}
fn next_token(&mut self) -> Result<Option<Token>, BellronosError> {
self.skip_whitespace();
if self.position >= self.input.len() {
return Ok(None);
}
let token = match self.current_char() {
'(' => {
self.advance();
Ok(Some(Token::LeftParen))
}
')' => {
self.advance();
Ok(Some(Token::RightParen))
}
'{' => {
self.advance();
Ok(Some(Token::LeftBrace))
}
'}' => {
self.advance();
Ok(Some(Token::RightBrace))
}
'[' => {
self.advance();
Ok(Some(Token::LeftBracket))
}
']' => {
self.advance();
Ok(Some(Token::RightBracket))
}
':' => {
self.advance();
Ok(Some(Token::Colon))
}
',' => {
self.advance();
Ok(Some(Token::Comma))
}
'.' => {
self.advance();
Ok(Some(Token::Dot))
}
'+' => {
self.advance();
Ok(Some(Token::Plus))
}
'-' => {
self.advance();
if self.current_char() == '>' {
self.advance();
Ok(Some(Token::Arrow))
} else {
Ok(Some(Token::Minus))
}
}
'*' => {
self.advance();
Ok(Some(Token::Multiply))
}
'/' => {
self.advance();
Ok(Some(Token::Divide))
}
'=' => {
self.advance();
if self.current_char() == '=' {
self.advance();
Ok(Some(Token::Equals))
} else {
Ok(Some(Token::Set))
}
}
'!' => {
self.advance();
if self.current_char() == '=' {
self.advance();
Ok(Some(Token::NotEquals))
} else {
Err(BellronosError::Parser(format!(
"Unexpected character: {}",
self.current_char()
)))
}
}
'<' => {
self.advance();
if self.current_char() == '=' {
self.advance();
Ok(Some(Token::LessThanOrEqual))
} else {
Ok(Some(Token::LessThan))
}
}
'>' => {
self.advance();
if self.current_char() == '=' {
self.advance();
Ok(Some(Token::GreaterThanOrEqual))
} else {
Ok(Some(Token::GreaterThan))
}
}
'\n' => {
self.advance_line();
Ok(Some(Token::Newline))
}
'"' => self.tokenize_string(),
'0'..='9' => self.tokenize_number(),
'a'..='z' | 'A'..='Z' | '_' => self.tokenize_identifier(),
'#' => {
while self.current_char() != '\n' && self.position < self.input.len() {
self.advance();
}
self.next_token()
}
_ => Err(BellronosError::Parser(format!(
"Unexpected character: {}",
self.current_char()
))),
}?;
Ok(token)
}
fn tokenize_string(&mut self) -> Result<Option<Token>, BellronosError> {
self.advance(); // Skip opening quote
let start = self.position;
while self.current_char() != '"' && self.position < self.input.len() {
if self.current_char() == '\n' {
return Err(BellronosError::Parser(format!(
"Unexpected character: {}",
self.current_char()
)));
}
self.advance();
}
if self.position >= self.input.len() {
return Err(BellronosError::Parser(format!(
"Unexpected character: {}",
self.current_char()
)));
}
let value: String = self.input[start..self.position].iter().collect();
self.advance(); // Skip closing quote
Ok(Some(Token::String(value)))
}
fn tokenize_number(&mut self) -> Result<Option<Token>, BellronosError> {
let start = self.position;
while self.position < self.input.len()
&& (self.current_char().is_digit(10) || self.current_char() == '.')
{
self.advance();
}
let value: String = self.input[start..self.position].iter().collect();
value
.parse::<f64>()
.map(|n| Some(Token::Number(n)))
.map_err(|_| {
BellronosError::Parser(format!("Unexpected character: {}", self.current_char()))
})
}
fn tokenize_identifier(&mut self) -> Result<Option<Token>, BellronosError> {
let start = self.position;
while self.position < self.input.len()
&& (self.current_char().is_alphanumeric() || self.current_char() == '_')
{
self.advance();
}
let value: String = self.input[start..self.position].iter().collect();
Ok(Some(match value.as_str() {
"import" => Token::Import,
"define" => Token::Define,
"class" => Token::Class,
"set" => Token::Set,
"to" => Token::To,
"if" => Token::If,
"else" => Token::Else,
"while" => Token::While,
"for" => Token::For,
"in" => Token::In,
"return" => Token::Return,
"async" => Token::Async,
"await" => Token::Await,
"yield" => Token::Yield,
"closure" => Token::Closure,
"true" => Token::True,
"false" => Token::False,
_ => Token::Identifier(value),
}))
}
fn current_char(&self) -> char {
self.input[self.position]
}
fn advance(&mut self) {
self.position += 1;
self.column += 1;
}
fn advance_line(&mut self) {
self.position += 1;
self.line += 1;
self.column = 1;
}
fn skip_whitespace(&mut self) {
while self.position < self.input.len()
&& self.current_char().is_whitespace()
&& self.current_char() != '\n'
{
self.advance();
}
}
}

1
src/lexer/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod lexer;

View File

@ -0,0 +1 @@
pub mod package_manager;

View File

@ -0,0 +1,250 @@
// Copyright (C) 2024 Bellande Architecture Mechanism Research Innovation Center, Ronaldson Bellande
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error::error::BellronosError;
use reqwest;
use serde::{Deserialize, Serialize};
use std::fs::{self, File};
use std::io::{Error as IoError, Write};
use std::path::PathBuf;
const PACKAGE_REGISTRY_URL: &str =
"https://bellande-architecture-mechanism-research-innovation-center.org/bellronos/packages";
const GITHUB_REPO_URL: &str = "https://github.com/Architecture-Mechanism/bellronos_package_manager";
#[derive(Serialize, Deserialize)]
struct PackageMetadata {
name: String,
version: String,
dependencies: Vec<String>,
}
pub struct PackageManager {
package_dir: PathBuf,
}
impl PackageManager {
pub fn new(package_dir: String) -> Self {
PackageManager {
package_dir: PathBuf::from(package_dir),
}
}
pub fn install_package(&self, package_name: &str) -> Result<(), BellronosError> {
println!("Installing package: {}", package_name);
// Fetch package metadata
let metadata = self.fetch_package_metadata(package_name)?;
// Download package
let package_content = self.download_package(&metadata)?;
// Install dependencies
for dependency in &metadata.dependencies {
self.install_package(dependency)?;
}
// Write package content
let package_path = self
.package_dir
.join(&metadata.name)
.with_extension("bellronos");
let mut file = File::create(&package_path).map_err(|e| {
BellronosError::IO(IoError::new(
e.kind(),
format!("Failed to create package file: {}", e),
))
})?;
file.write_all(package_content.as_bytes()).map_err(|e| {
BellronosError::IO(IoError::new(
e.kind(),
format!("Failed to write package content: {}", e),
))
})?;
println!("Successfully installed package: {}", package_name);
Ok(())
}
pub fn load_package(&self, package_name: &str) -> Result<String, BellronosError> {
let package_path = self
.package_dir
.join(package_name)
.with_extension("bellronos");
fs::read_to_string(&package_path).map_err(|e| {
BellronosError::IO(IoError::new(
e.kind(),
format!(
"Failed to read package file {}: {}",
package_path.display(),
e
),
))
})
}
pub fn list_installed_packages(&self) -> Result<Vec<String>, BellronosError> {
let entries = fs::read_dir(&self.package_dir).map_err(|e| {
BellronosError::IO(IoError::new(
e.kind(),
format!(
"Failed to read package directory {}: {}",
self.package_dir.display(),
e
),
))
})?;
let mut packages = Vec::new();
for entry in entries {
let entry = entry.map_err(|e| {
BellronosError::IO(IoError::new(
e.kind(),
format!("Failed to read directory entry: {}", e),
))
})?;
if let Some(file_name) = entry.path().file_stem() {
if let Some(name) = file_name.to_str() {
packages.push(name.to_string());
}
}
}
Ok(packages)
}
fn fetch_package_metadata(
&self,
package_name: &str,
) -> Result<PackageMetadata, BellronosError> {
let url = format!("{}/{}/metadata.json", PACKAGE_REGISTRY_URL, package_name);
let response = reqwest::blocking::get(&url).map_err(|e| {
BellronosError::Network(format!("Failed to fetch package metadata: {}", e))
})?;
if !response.status().is_success() {
return Err(BellronosError::Network(format!(
"Failed to fetch package metadata. Status: {}",
response.status()
)));
}
response
.json::<PackageMetadata>()
.map_err(|e| BellronosError::Parser(format!("Failed to parse package metadata: {}", e)))
}
fn download_package(&self, metadata: &PackageMetadata) -> Result<String, BellronosError> {
let url = format!(
"{}/{}/{}.bellronos",
PACKAGE_REGISTRY_URL, metadata.name, metadata.version
);
let response = reqwest::blocking::get(&url)
.map_err(|e| BellronosError::Network(format!("Failed to download package: {}", e)))?;
if !response.status().is_success() {
return Err(BellronosError::Network(format!(
"Failed to download package. Status: {}",
response.status()
)));
}
response
.text()
.map_err(|e| BellronosError::Network(format!("Failed to read package content: {}", e)))
}
pub fn update_package(&self, package_name: &str) -> Result<(), BellronosError> {
let installed_packages = self.list_installed_packages()?;
if !installed_packages.contains(&package_name.to_string()) {
return Err(BellronosError::Package(format!(
"Package {} is not installed",
package_name
)));
}
// Fetch latest metadata
let metadata = self.fetch_package_metadata(package_name)?;
// Check if update is needed
let current_version = self.get_installed_package_version(package_name)?;
if current_version == metadata.version {
println!("Package {} is already up to date", package_name);
return Ok(());
}
// Perform update
self.install_package(package_name)
}
fn get_installed_package_version(&self, package_name: &str) -> Result<String, BellronosError> {
let package_path = self
.package_dir
.join(package_name)
.with_extension("bellronos");
let content = fs::read_to_string(&package_path).map_err(|e| {
BellronosError::IO(IoError::new(
e.kind(),
format!(
"Failed to read package file {}: {}",
package_path.display(),
e
),
))
})?;
// Extract version from package content
content
.lines()
.find(|line| line.starts_with("# Version:"))
.and_then(|line| line.split(':').nth(1))
.map(|version| version.trim().to_string())
.ok_or_else(|| BellronosError::Parser("Failed to extract package version".to_string()))
}
pub fn search_packages(&self, query: &str) -> Result<Vec<String>, BellronosError> {
let url = format!("{}/search?q={}", PACKAGE_REGISTRY_URL, query);
let response = reqwest::blocking::get(&url)
.map_err(|e| BellronosError::Network(format!("Failed to search packages: {}", e)))?;
if !response.status().is_success() {
return Err(BellronosError::Network(format!(
"Failed to search packages. Status: {}",
response.status()
)));
}
response
.json::<Vec<String>>()
.map_err(|e| BellronosError::Parser(format!("Failed to parse search results: {}", e)))
}
pub fn get_package_info(&self, package_name: &str) -> Result<String, BellronosError> {
let url = format!("{}/{}/README.md", GITHUB_REPO_URL, package_name);
let response = reqwest::blocking::get(&url)
.map_err(|e| BellronosError::Network(format!("Failed to fetch package info: {}", e)))?;
if !response.status().is_success() {
return Err(BellronosError::Network(format!(
"Failed to fetch package info. Status: {}",
response.status()
)));
}
response
.text()
.map_err(|e| BellronosError::Network(format!("Failed to read package info: {}", e)))
}
}

1
src/parser/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod parser;

455
src/parser/parser.rs Normal file
View File

@ -0,0 +1,455 @@
// Copyright (C) 2024 Bellande Architecture Mechanism Research Innovation Center, Ronaldson Bellande
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::ast::ast::ASTNode;
use crate::error::error::BellronosError;
use crate::lexer::lexer::Token;
use crate::type_system::type_system::Type;
pub struct Parser {
tokens: Vec<Token>,
position: usize,
}
impl Parser {
pub fn new(tokens: Vec<Token>) -> Self {
Parser {
tokens,
position: 0,
}
}
pub fn parse(&mut self) -> Result<ASTNode, BellronosError> {
let mut body = Vec::new();
while self.position < self.tokens.len() {
body.push(self.parse_statement()?);
}
Ok(ASTNode::Module { body })
}
fn parse_statement(&mut self) -> Result<ASTNode, BellronosError> {
match self.current_token() {
Token::Import => self.parse_import(),
Token::Define => self.parse_function_def(),
Token::Class => self.parse_class_def(),
Token::Set => self.parse_assignment(),
Token::If => self.parse_if(),
Token::While => self.parse_while(),
Token::For => self.parse_for(),
Token::Return => self.parse_return(),
Token::Async => self.parse_async(),
Token::Yield => self.parse_yield(),
Token::Closure => self.parse_closure(),
_ => self.parse_expression(),
}
}
fn parse_import(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume 'import'
let mut names = Vec::new();
while let Token::Identifier(name) = self.current_token() {
names.push(name.clone());
self.advance();
if self.current_token() == Token::Comma {
self.advance();
} else {
break;
}
}
self.expect_token(Token::Newline)?;
Ok(ASTNode::Import { names })
}
fn parse_function_def(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume 'define'
let name = self.expect_identifier()?;
let args = self.parse_function_args()?;
let return_type = self.parse_return_type()?;
self.expect_token(Token::Colon)?;
self.expect_token(Token::Newline)?;
let body = self.parse_block()?;
Ok(ASTNode::FunctionDef {
name,
args,
return_type,
body,
})
}
fn parse_class_def(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume 'class'
let name = self.expect_identifier()?;
self.expect_token(Token::Colon)?;
self.expect_token(Token::Newline)?;
let methods = self.parse_block()?;
Ok(ASTNode::ClassDef { name, methods })
}
fn parse_assignment(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume 'set'
let target = self.expect_identifier()?;
self.expect_token(Token::To)?;
let value = Box::new(self.parse_expression()?);
self.expect_token(Token::Newline)?;
Ok(ASTNode::Assign { target, value })
}
fn parse_if(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume 'if'
let condition = Box::new(self.parse_expression()?);
self.expect_token(Token::Colon)?;
self.expect_token(Token::Newline)?;
let body = self.parse_block()?;
let mut orelse = Vec::new();
if self.current_token() == Token::Else {
self.advance();
self.expect_token(Token::Colon)?;
self.expect_token(Token::Newline)?;
orelse = self.parse_block()?;
}
Ok(ASTNode::If {
condition,
body,
orelse,
})
}
fn parse_while(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume 'while'
let condition = Box::new(self.parse_expression()?);
self.expect_token(Token::Colon)?;
self.expect_token(Token::Newline)?;
let body = self.parse_block()?;
Ok(ASTNode::While { condition, body })
}
fn parse_for(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume 'for'
let target = self.expect_identifier()?;
self.expect_token(Token::In)?;
let iter = Box::new(self.parse_expression()?);
self.expect_token(Token::Colon)?;
self.expect_token(Token::Newline)?;
let body = self.parse_block()?;
Ok(ASTNode::For { target, iter, body })
}
fn parse_return(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume 'return'
let value = if self.current_token() == Token::Newline {
None
} else {
Some(Box::new(self.parse_expression()?))
};
self.expect_token(Token::Newline)?;
Ok(ASTNode::Return { value })
}
fn parse_async(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume 'async'
self.expect_token(Token::Define)?;
let function = self.parse_function_def()?;
if let ASTNode::FunctionDef {
name,
args,
return_type,
body,
} = function
{
Ok(ASTNode::Async {
body: vec![ASTNode::FunctionDef {
name,
args,
return_type,
body,
}],
})
} else {
Err(BellronosError::Parser(
"Expected function definition after 'async'".to_string(),
))
}
}
fn parse_yield(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume 'yield'
let value = Box::new(self.parse_expression()?);
self.expect_token(Token::Newline)?;
Ok(ASTNode::Yield { value })
}
fn parse_closure(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume 'closure'
let params = self.parse_function_args()?;
self.expect_token(Token::Colon)?;
let body = Box::new(self.parse_expression()?);
Ok(ASTNode::Closure { params, body })
}
fn parse_expression(&mut self) -> Result<ASTNode, BellronosError> {
self.parse_binary_operation()
}
fn parse_binary_operation(&mut self) -> Result<ASTNode, BellronosError> {
let mut left = self.parse_unary()?;
while matches!(
self.current_token(),
Token::Plus
| Token::Minus
| Token::Multiply
| Token::Divide
| Token::Equals
| Token::NotEquals
| Token::LessThan
| Token::GreaterThan
| Token::LessThanOrEqual
| Token::GreaterThanOrEqual
) {
let op = format!("{:?}", self.current_token());
self.advance();
let right = self.parse_unary()?;
left = ASTNode::BinOp {
left: Box::new(left),
op,
right: Box::new(right),
};
}
Ok(left)
}
fn parse_unary(&mut self) -> Result<ASTNode, BellronosError> {
match self.current_token() {
Token::Minus => {
self.advance();
let expr = self.parse_unary()?;
Ok(ASTNode::BinOp {
left: Box::new(ASTNode::Num { value: 0.0 }),
op: "-".to_string(),
right: Box::new(expr),
})
}
_ => self.parse_primary(),
}
}
fn parse_primary(&mut self) -> Result<ASTNode, BellronosError> {
match self.current_token() {
Token::Identifier(name) => {
self.advance();
if self.current_token() == Token::LeftParen {
self.parse_function_call(&name)
} else {
Ok(ASTNode::Name { id: name })
}
}
Token::String(value) => {
self.advance();
Ok(ASTNode::Str { value })
}
Token::Number(value) => {
self.advance();
Ok(ASTNode::Num { value })
}
Token::True => {
self.advance();
Ok(ASTNode::Bool { value: true })
}
Token::False => {
self.advance();
Ok(ASTNode::Bool { value: false })
}
Token::LeftParen => {
self.advance();
let expr = self.parse_expression()?;
self.expect_token(Token::RightParen)?;
Ok(expr)
}
Token::LeftBracket => self.parse_list(),
Token::LeftBrace => self.parse_dict(),
_ => Err(BellronosError::Parser(format!(
"Unexpected token: {:?}",
self.current_token()
))),
}
}
fn parse_function_call(&mut self, name: &str) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume '('
let mut args = Vec::new();
if self.current_token() != Token::RightParen {
loop {
args.push(self.parse_expression()?);
if self.current_token() == Token::Comma {
self.advance();
} else {
break;
}
}
}
self.expect_token(Token::RightParen)?;
Ok(ASTNode::Call {
func: name.to_string(),
args,
})
}
fn parse_list(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume '['
let mut elements = Vec::new();
if self.current_token() != Token::RightBracket {
loop {
elements.push(self.parse_expression()?);
if self.current_token() == Token::Comma {
self.advance();
} else {
break;
}
}
}
self.expect_token(Token::RightBracket)?;
Ok(ASTNode::List { elements })
}
fn parse_dict(&mut self) -> Result<ASTNode, BellronosError> {
self.advance(); // Consume '{'
let mut pairs = Vec::new();
if self.current_token() != Token::RightBrace {
loop {
let key = self.parse_expression()?;
self.expect_token(Token::Colon)?;
let value = self.parse_expression()?;
pairs.push((key, value));
if self.current_token() == Token::Comma {
self.advance();
} else {
break;
}
}
}
self.expect_token(Token::RightBrace)?;
Ok(ASTNode::Dict { pairs })
}
fn parse_function_args(&mut self) -> Result<Vec<(String, Type)>, BellronosError> {
let mut args = Vec::new();
self.expect_token(Token::LeftParen)?;
if self.current_token() != Token::RightParen {
loop {
let name = self.expect_identifier()?;
self.expect_token(Token::Colon)?;
let type_ = self.parse_type()?;
args.push((name, type_));
if self.current_token() == Token::Comma {
self.advance();
} else {
break;
}
}
}
self.expect_token(Token::RightParen)?;
Ok(args)
}
fn parse_return_type(&mut self) -> Result<Type, BellronosError> {
if self.current_token() == Token::Arrow {
self.advance();
self.parse_type()
} else {
Ok(Type::None)
}
}
fn parse_type(&mut self) -> Result<Type, BellronosError> {
match self.current_token() {
Token::Identifier(name) => {
self.advance();
match name.as_str() {
"int" => Ok(Type::Int),
"float" => Ok(Type::Float),
"string" => Ok(Type::String),
"bool" => Ok(Type::Bool),
"list" => {
self.expect_token(Token::LeftBracket)?;
let inner_type = self.parse_type()?;
self.expect_token(Token::RightBracket)?;
Ok(Type::List(Box::new(inner_type)))
}
"dict" => {
self.expect_token(Token::LeftBrace)?;
let key_type = self.parse_type()?;
self.expect_token(Token::Colon)?;
let value_type = self.parse_type()?;
self.expect_token(Token::RightBrace)?;
Ok(Type::Dict(Box::new(key_type), Box::new(value_type)))
}
_ => Ok(Type::Custom(name)),
}
}
_ => Err(BellronosError::Parser("Expected type".to_string())),
}
}
fn parse_block(&mut self) -> Result<Vec<ASTNode>, BellronosError> {
let mut body = Vec::new();
while self.current_token() != Token::EOF && !matches!(self.current_token(), Token::Else) {
body.push(self.parse_statement()?);
}
Ok(body)
}
fn expect_identifier(&mut self) -> Result<String, BellronosError> {
if let Token::Identifier(name) = self.current_token() {
self.advance();
Ok(name)
} else {
Err(BellronosError::Parser(format!(
"Expected identifier, found {:?}",
self.current_token()
)))
}
}
fn expect_token(&mut self, expected: Token) -> Result<(), BellronosError> {
if self.current_token() == expected {
self.advance();
Ok(())
} else {
Err(BellronosError::Parser(format!(
"Expected {:?}, found {:?}",
expected,
self.current_token()
)))
}
}
fn current_token(&self) -> Token {
self.tokens
.get(self.position)
.cloned()
.unwrap_or(Token::EOF)
}
fn advance(&mut self) {
self.position += 1;
}
}
impl std::fmt::Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}

View File

@ -0,0 +1 @@
pub mod standard_library;

View File

@ -0,0 +1,102 @@
// Copyright (C) 2024 Bellande Architecture Mechanism Research Innovation Center, Ronaldson Bellande
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::interpreter::interpreter::Value;
use std::collections::HashMap;
pub struct StandardLibrary {
modules: HashMap<String, HashMap<String, Value>>,
}
impl StandardLibrary {
pub fn new() -> Self {
let mut stdlib = StandardLibrary {
modules: HashMap::new(),
};
stdlib.init_math();
stdlib.init_io();
stdlib.init_string();
stdlib
}
fn init_math(&mut self) {
let mut math = HashMap::new();
math.insert("pi".to_string(), Value::Float(std::f64::consts::PI));
math.insert("e".to_string(), Value::Float(std::f64::consts::E));
math.insert(
"sqrt".to_string(),
Value::Function(
vec!["x".to_string()],
vec![],
std::rc::Rc::new(std::cell::RefCell::new(HashMap::new())),
),
);
self.modules.insert("math".to_string(), math);
}
fn init_io(&mut self) {
let mut io = HashMap::new();
io.insert(
"print".to_string(),
Value::Function(
vec!["args".to_string()],
vec![],
std::rc::Rc::new(std::cell::RefCell::new(HashMap::new())),
),
);
io.insert(
"input".to_string(),
Value::Function(
vec!["prompt".to_string()],
vec![],
std::rc::Rc::new(std::cell::RefCell::new(HashMap::new())),
),
);
self.modules.insert("io".to_string(), io);
}
fn init_string(&mut self) {
let mut string = HashMap::new();
string.insert(
"length".to_string(),
Value::Function(
vec!["s".to_string()],
vec![],
std::rc::Rc::new(std::cell::RefCell::new(HashMap::new())),
),
);
string.insert(
"to_upper".to_string(),
Value::Function(
vec!["s".to_string()],
vec![],
std::rc::Rc::new(std::cell::RefCell::new(HashMap::new())),
),
);
string.insert(
"to_lower".to_string(),
Value::Function(
vec!["s".to_string()],
vec![],
std::rc::Rc::new(std::cell::RefCell::new(HashMap::new())),
),
);
self.modules.insert("string".to_string(), string);
}
pub fn get_module(&self, name: &str) -> Option<&HashMap<String, Value>> {
self.modules.get(name)
}
}

1
src/type_system/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod type_system;

View File

@ -0,0 +1,507 @@
// Copyright (C) 2024 Bellande Architecture Mechanism Research Innovation Center, Ronaldson Bellande
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::ast::ast::ASTNode;
use crate::error::error::BellronosError;
use std::collections::HashMap;
use std::str::FromStr;
#[derive(Debug, Clone, PartialEq)]
pub enum InteropType {
CInt,
CFloat,
CString,
PyInt,
PyFloat,
PyString,
PyList,
PyDict,
JsNumber,
JsString,
JsBoolean,
JsArray,
JsObject,
Unknown,
}
#[derive(Debug, Clone, PartialEq)]
pub enum InteropLanguage {
C,
Python,
JavaScript,
}
impl FromStr for InteropLanguage {
type Err = BellronosError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"c" => Ok(InteropLanguage::C),
"python" => Ok(InteropLanguage::Python),
"javascript" | "js" => Ok(InteropLanguage::JavaScript),
_ => Err(BellronosError::Type(format!(
"Unknown interop language: {}",
s
))),
}
}
}
impl InteropLanguage {
pub fn infer_type(&self, code: &str) -> Result<InteropType, BellronosError> {
match self {
InteropLanguage::C => {
if code.contains("int") {
Ok(InteropType::CInt)
} else if code.contains("float") {
Ok(InteropType::CFloat)
} else if code.contains("char*") {
Ok(InteropType::CString)
} else {
Ok(InteropType::Unknown)
}
}
InteropLanguage::Python => {
if code.contains("int(") {
Ok(InteropType::PyInt)
} else if code.contains("float(") {
Ok(InteropType::PyFloat)
} else if code.contains("str(") {
Ok(InteropType::PyString)
} else if code.contains("list(") {
Ok(InteropType::PyList)
} else if code.contains("dict(") {
Ok(InteropType::PyDict)
} else {
Ok(InteropType::Unknown)
}
}
InteropLanguage::JavaScript => {
if code.contains("Number(") {
Ok(InteropType::JsNumber)
} else if code.contains("String(") {
Ok(InteropType::JsString)
} else if code.contains("Boolean(") {
Ok(InteropType::JsBoolean)
} else if code.contains("Array(") {
Ok(InteropType::JsArray)
} else if code.contains("Object(") {
Ok(InteropType::JsObject)
} else {
Ok(InteropType::Unknown)
}
}
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Type {
Int,
Float,
String,
Bool,
List(Box<Type>),
Dict(Box<Type>, Box<Type>),
Function(Vec<Type>, Box<Type>),
Class(String),
Instance(String),
None,
Any,
Custom(String),
Interop(InteropType),
}
#[derive(Clone)]
pub struct TypeChecker {
type_env: HashMap<String, Type>,
class_env: HashMap<String, HashMap<String, Type>>,
}
impl TypeChecker {
pub fn new() -> Self {
TypeChecker {
type_env: HashMap::new(),
class_env: HashMap::new(),
}
}
pub fn check(&mut self, node: &ASTNode) -> Result<Type, BellronosError> {
match node {
ASTNode::Module { body } => {
for stmt in body {
self.check(stmt)?;
}
Ok(Type::None)
}
ASTNode::Import { names } => {
for name in names {
self.type_env.insert(name.clone(), Type::Any);
}
Ok(Type::None)
}
ASTNode::FunctionDef {
name,
args,
return_type,
body,
} => {
let arg_types: Vec<Type> = args.iter().map(|(_, t)| t.clone()).collect();
let func_type = Type::Function(arg_types.clone(), Box::new(return_type.clone()));
self.type_env.insert(name.clone(), func_type);
let mut func_checker = self.clone();
for (arg_name, arg_type) in args {
func_checker
.type_env
.insert(arg_name.clone(), arg_type.clone());
}
for stmt in body {
let stmt_type = func_checker.check(stmt)?;
if let ASTNode::Return { .. } = stmt {
if stmt_type != *return_type {
return Err(BellronosError::Type(format!(
"Function {} return type mismatch: expected {:?}, found {:?}",
name, return_type, stmt_type
)));
}
}
}
Ok(Type::None)
}
ASTNode::ClassDef { name, methods } => {
let mut class_methods = HashMap::new();
for method in methods {
if let ASTNode::FunctionDef {
name: method_name,
args,
return_type,
..
} = method
{
let arg_types: Vec<Type> = args.iter().map(|(_, t)| t.clone()).collect();
class_methods.insert(
method_name.clone(),
Type::Function(arg_types, Box::new(return_type.clone())),
);
}
}
self.class_env.insert(name.clone(), class_methods);
self.type_env
.insert(name.clone(), Type::Class(name.clone()));
Ok(Type::None)
}
ASTNode::Assign { target, value } => {
let value_type = self.check(value)?;
self.type_env.insert(target.clone(), value_type);
Ok(Type::None)
}
ASTNode::Expr { value } => self.check(value),
ASTNode::Call { func, args } => {
let func_type =
self.type_env.get(func).cloned().ok_or_else(|| {
BellronosError::Type(format!("Undefined function: {}", func))
})?;
if let Type::Function(param_types, return_type) = func_type {
if args.len() != param_types.len() {
return Err(BellronosError::Type(format!(
"Function {} expects {} arguments, but {} were given",
func,
param_types.len(),
args.len()
)));
}
for (arg, expected_type) in args.iter().zip(param_types.iter()) {
let arg_type = self.check(arg)?;
if !self.is_compatible(&arg_type, expected_type) {
return Err(BellronosError::Type(format!(
"Type mismatch: expected {:?}, found {:?}",
expected_type, arg_type
)));
}
}
Ok(*return_type)
} else {
Err(BellronosError::Type(format!("{} is not a function", func)))
}
}
ASTNode::Str { .. } => Ok(Type::String),
ASTNode::Num { .. } => Ok(Type::Float),
ASTNode::Bool { .. } => Ok(Type::Bool),
ASTNode::Name { id } => self
.type_env
.get(id)
.cloned()
.ok_or_else(|| BellronosError::Type(format!("Undefined variable: {}", id))),
ASTNode::BinOp { left, op, right } => {
let left_type = self.check(left)?;
let right_type = self.check(right)?;
self.check_binary_op(&left_type, op, &right_type)
}
ASTNode::If {
condition,
body,
orelse,
} => {
let cond_type = self.check(condition)?;
if cond_type != Type::Bool {
return Err(BellronosError::Type(
"If condition must be a boolean".to_string(),
));
}
for stmt in body {
self.check(stmt)?;
}
for stmt in orelse {
self.check(stmt)?;
}
Ok(Type::None)
}
ASTNode::While { condition, body } => {
let cond_type = self.check(condition)?;
if cond_type != Type::Bool {
return Err(BellronosError::Type(
"While condition must be a boolean".to_string(),
));
}
for stmt in body {
self.check(stmt)?;
}
Ok(Type::None)
}
ASTNode::For { target, iter, body } => {
let iter_type = self.check(iter)?;
if let Type::List(element_type) = iter_type {
self.type_env.insert(target.clone(), *element_type);
for stmt in body {
self.check(stmt)?;
}
Ok(Type::None)
} else {
Err(BellronosError::Type(
"For loop iterable must be a list".to_string(),
))
}
}
ASTNode::Return { value } => {
if let Some(v) = value {
self.check(v)
} else {
Ok(Type::None)
}
}
ASTNode::Closure { params, body } => {
let param_types: Vec<Type> = params.iter().map(|(_, t)| t.clone()).collect();
let mut closure_checker = self.clone();
for (param_name, param_type) in params {
closure_checker
.type_env
.insert(param_name.clone(), param_type.clone());
}
let return_type = closure_checker.check(body)?;
Ok(Type::Function(param_types, Box::new(return_type)))
}
ASTNode::Generator { body } => {
for stmt in body {
self.check(stmt)?;
}
Ok(Type::List(Box::new(Type::Any)))
}
ASTNode::Yield { value } => self.check(value),
ASTNode::Async { body } => {
for stmt in body {
self.check(stmt)?;
}
Ok(Type::Any)
}
ASTNode::Await { value } => self.check(value),
ASTNode::List { elements } => {
if elements.is_empty() {
Ok(Type::List(Box::new(Type::Any)))
} else {
let first_type = self.check(&elements[0])?;
for element in elements.iter().skip(1) {
let element_type = self.check(element)?;
if !self.is_compatible(&element_type, &first_type) {
return Err(BellronosError::Type(
"All list elements must have compatible types".to_string(),
));
}
}
Ok(Type::List(Box::new(first_type)))
}
}
ASTNode::Dict { pairs } => {
if pairs.is_empty() {
Ok(Type::Dict(Box::new(Type::Any), Box::new(Type::Any)))
} else {
let (first_key, first_value) = &pairs[0];
let key_type = self.check(first_key)?;
let value_type = self.check(first_value)?;
for (key, value) in pairs.iter().skip(1) {
let k_type = self.check(key)?;
let v_type = self.check(value)?;
if !self.is_compatible(&k_type, &key_type)
|| !self.is_compatible(&v_type, &value_type)
{
return Err(BellronosError::Type(
"All dictionary keys must have compatible types, and all values must have compatible types".to_string(),
));
}
}
Ok(Type::Dict(Box::new(key_type), Box::new(value_type)))
}
}
ASTNode::Attribute { value, attr } => {
let value_type = self.check(value)?;
if let Type::Instance(class_name) = value_type {
if let Some(class_methods) = self.class_env.get(&class_name) {
class_methods.get(attr).cloned().ok_or_else(|| {
BellronosError::Type(format!(
"Attribute '{}' not found in class '{}'",
attr, class_name
))
})
} else {
Err(BellronosError::Type(format!(
"Class '{}' not found",
class_name
)))
}
} else {
Err(BellronosError::Type(format!(
"Cannot access attribute '{}' on non-instance type {:?}",
attr, value_type
)))
}
}
ASTNode::InteropCall { language, code } => {
let interop_lang = InteropLanguage::from_str(language)?;
Ok(Type::Interop(interop_lang.infer_type(code)?))
}
}
}
fn check_binary_op(&self, left: &Type, op: &str, right: &Type) -> Result<Type, BellronosError> {
match (left, op, right) {
(Type::Int, "+", Type::Int) => Ok(Type::Int),
(Type::Float, "+", Type::Float) => Ok(Type::Float),
(Type::String, "+", Type::String) => Ok(Type::String),
(Type::Int, "-", Type::Int) => Ok(Type::Int),
(Type::Float, "-", Type::Float) => Ok(Type::Float),
(Type::Int, "*", Type::Int) => Ok(Type::Int),
(Type::Float, "*", Type::Float) => Ok(Type::Float),
(Type::Int, "/", Type::Int) => Ok(Type::Float),
(Type::Float, "/", Type::Float) => Ok(Type::Float),
(Type::Int | Type::Float, op, Type::Int | Type::Float)
if op == ">" || op == "<" || op == ">=" || op == "<=" =>
{
Ok(Type::Bool)
}
(_, "==" | "!=", _) => Ok(Type::Bool),
_ => Err(BellronosError::Type(format!(
"Invalid operation: {:?} {} {:?}",
left, op, right
))),
}
}
fn is_compatible(&self, actual: &Type, expected: &Type) -> bool {
match (actual, expected) {
(Type::Any, _) | (_, Type::Any) => true,
(Type::Int, Type::Float) | (Type::Float, Type::Int) => true,
(Type::List(a), Type::List(b)) => self.is_compatible(a, b),
(Type::Dict(ka, va), Type::Dict(kb, vb)) => {
self.is_compatible(ka, kb) && self.is_compatible(va, vb)
}
(Type::Function(params_a, return_a), Type::Function(params_b, return_b)) => {
params_a.len() == params_b.len()
&& params_a
.iter()
.zip(params_b.iter())
.all(|(a, b)| self.is_compatible(a, b))
&& self.is_compatible(return_a, return_b)
}
(Type::Interop(a), Type::Interop(b)) => a == b,
(Type::Interop(_), _) | (_, Type::Interop(_)) => false, // Interop types are only compatible with themselves
(a, b) => a == b,
}
}
pub fn get_type(&self, name: &str) -> Option<&Type> {
self.type_env.get(name)
}
pub fn set_type(&mut self, name: String, typ: Type) {
self.type_env.insert(name, typ);
}
pub fn get_class_method(&self, class_name: &str, method_name: &str) -> Option<&Type> {
self.class_env
.get(class_name)
.and_then(|methods| methods.get(method_name))
}
pub fn add_class_method(&mut self, class_name: &str, method_name: String, method_type: Type) {
self.class_env
.entry(class_name.to_string())
.or_insert_with(HashMap::new)
.insert(method_name, method_type);
}
}
impl From<InteropType> for Type {
fn from(interop_type: InteropType) -> Self {
match interop_type {
InteropType::CInt | InteropType::PyInt => Type::Int,
InteropType::CFloat | InteropType::PyFloat | InteropType::JsNumber => Type::Float,
InteropType::CString | InteropType::PyString | InteropType::JsString => Type::String,
InteropType::PyList | InteropType::JsArray => Type::List(Box::new(Type::Any)),
InteropType::PyDict | InteropType::JsObject => {
Type::Dict(Box::new(Type::Any), Box::new(Type::Any))
}
InteropType::JsBoolean => Type::Bool,
InteropType::Unknown => Type::Any,
}
}
}
pub fn interop_type_to_bellronos_type(interop_type: InteropType) -> Type {
Type::from(interop_type)
}
pub fn bellronos_type_to_interop_type(
bellronos_type: &Type,
language: &InteropLanguage,
) -> InteropType {
match (bellronos_type, language) {
(Type::Int, InteropLanguage::C) => InteropType::CInt,
(Type::Float, InteropLanguage::C) => InteropType::CFloat,
(Type::String, InteropLanguage::C) => InteropType::CString,
(Type::Int, InteropLanguage::Python) => InteropType::PyInt,
(Type::Float, InteropLanguage::Python) => InteropType::PyFloat,
(Type::String, InteropLanguage::Python) => InteropType::PyString,
(Type::List(_), InteropLanguage::Python) => InteropType::PyList,
(Type::Dict(_, _), InteropLanguage::Python) => InteropType::PyDict,
(Type::Int | Type::Float, InteropLanguage::JavaScript) => InteropType::JsNumber,
(Type::String, InteropLanguage::JavaScript) => InteropType::JsString,
(Type::Bool, InteropLanguage::JavaScript) => InteropType::JsBoolean,
(Type::List(_), InteropLanguage::JavaScript) => InteropType::JsArray,
(Type::Dict(_, _), InteropLanguage::JavaScript) => InteropType::JsObject,
_ => InteropType::Unknown,
}
}