Add functions and a print function
This commit is contained in:
parent
86c2b13d1a
commit
8b60677123
@ -1 +1,3 @@
|
||||
print();
|
||||
let otus = "Hello, world!";
|
||||
let dotus = otus;
|
||||
print(dotus);
|
@ -2,9 +2,10 @@ use std::collections::HashMap;
|
||||
|
||||
use super::errors::CompilerError;
|
||||
use super::parser::{Expression, LiteralPattern, ParsedReid, Pattern, Position, Statement};
|
||||
use super::vm::VariableType;
|
||||
use super::vm::{BuiltinFunctionDef, FunctionDef, FunctionSignature, VariableType};
|
||||
|
||||
type Variable = (HeapID, VariableType);
|
||||
pub type FuncID = usize;
|
||||
pub type HeapID = usize;
|
||||
pub type RegID = usize;
|
||||
|
||||
@ -18,6 +19,7 @@ pub enum Command {
|
||||
AssignVariable(HeapID, RegID), // Assign variable from registery at RegID
|
||||
VarToReg(HeapID, RegID), // Bring Variable to registery at RegID
|
||||
StringLit(String), // Bring String Literal to Stack
|
||||
FunctionCall(FuncID), // Call Function at FuncID
|
||||
}
|
||||
|
||||
pub struct Compiler {
|
||||
@ -40,11 +42,22 @@ impl Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_builtin_functions<T: Into<Vec<FunctionSignature>>>(mut self, list: T) -> Compiler {
|
||||
self.add_builtin_functions(list.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn compile(mut self) -> Result<CompiledReid, CompilerError> {
|
||||
self.handle_expression(self.parsed.0.clone())?;
|
||||
Ok(CompiledReid { list: self.list })
|
||||
}
|
||||
|
||||
pub fn add_builtin_functions<T: Into<Vec<FunctionSignature>>>(&mut self, list: T) {
|
||||
for func in list.into() {
|
||||
self.root_scope.add_builtin_function(func);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_expression(
|
||||
&mut self,
|
||||
exp: Expression,
|
||||
@ -62,7 +75,26 @@ impl Compiler {
|
||||
self.list.push(Command::EndScope);
|
||||
Ok(None)
|
||||
}
|
||||
Expression::FunctionCall(..) => Err(CompilerError::Fatal),
|
||||
Expression::FunctionCall(pos, name, args) => {
|
||||
let mut arguments = Vec::new();
|
||||
|
||||
for expr in args {
|
||||
if let Some(vtype) = self.handle_expression(expr)? {
|
||||
arguments.push(vtype);
|
||||
} else {
|
||||
return Err(CompilerError::CanNotAssignVoidType);
|
||||
}
|
||||
}
|
||||
if let Some(func) = self
|
||||
.root_scope
|
||||
.find_function(&FunctionSignature::new(name.clone(), arguments.clone()))
|
||||
{
|
||||
self.list.push(Command::FunctionCall(func.0));
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(CompilerError::FunctionNotFound(pos, name, arguments))
|
||||
}
|
||||
}
|
||||
Expression::ValueRef(_, val) => match val {
|
||||
Pattern::IdentPattern(pos, ident) => {
|
||||
if let Some(var) = self.root_scope.get(ident.clone()) {
|
||||
@ -123,6 +155,7 @@ impl Compiler {
|
||||
pub struct Scope {
|
||||
counter: HeapID,
|
||||
variables: HashMap<String, Variable>,
|
||||
functions: Vec<FunctionSignature>,
|
||||
inner_scope: Option<Box<Scope>>,
|
||||
}
|
||||
|
||||
@ -141,6 +174,25 @@ impl Scope {
|
||||
}
|
||||
}
|
||||
|
||||
fn find_function(&self, signature: &FunctionSignature) -> Option<(usize, &FunctionSignature)> {
|
||||
let mut found = None;
|
||||
for (idx, func) in self.functions.iter().enumerate() {
|
||||
if func == signature {
|
||||
found = Some((idx, func));
|
||||
}
|
||||
}
|
||||
found
|
||||
}
|
||||
|
||||
fn add_builtin_function(&mut self, function: FunctionSignature) -> bool {
|
||||
if self.find_function(&function).is_some() {
|
||||
false
|
||||
} else {
|
||||
self.functions.push(function);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn add_var(
|
||||
&mut self,
|
||||
pos: Position,
|
||||
|
@ -3,6 +3,8 @@ use std::fmt;
|
||||
use std::fmt::Display;
|
||||
use std::io;
|
||||
|
||||
use super::vm::VariableType;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GenericError {
|
||||
StdIOError(io::Error),
|
||||
@ -64,6 +66,7 @@ pub enum CompilerError {
|
||||
InvalidScopeExit(Position),
|
||||
LetFailed(Position, Box<CompilerError>),
|
||||
CanNotAssignVoidType,
|
||||
FunctionNotFound(Position, String, Vec<VariableType>),
|
||||
}
|
||||
|
||||
impl CompilerError {
|
||||
@ -92,12 +95,35 @@ impl Display for CompilerError {
|
||||
CompilerError::LetFailed(pos, error) => {
|
||||
format!("Let statement failed at {}:\n {}", pos, error)
|
||||
}
|
||||
CompilerError::CanNotAssignVoidType => format!("Can not assign void type to variable"),
|
||||
CompilerError::CanNotAssignVoidType => format!("Can not assign void type here"),
|
||||
CompilerError::FunctionNotFound(pos, name, params) => format!(
|
||||
"Function with signature {}{} not found at {}",
|
||||
name,
|
||||
ParamList(params.clone()),
|
||||
pos
|
||||
),
|
||||
};
|
||||
write!(f, "{}", text)
|
||||
}
|
||||
}
|
||||
|
||||
struct ParamList(Vec<VariableType>);
|
||||
|
||||
impl Display for ParamList {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut text = String::new();
|
||||
text += "(";
|
||||
for (idx, vtype) in self.0.iter().enumerate() {
|
||||
if idx > 0 {
|
||||
text += ", ";
|
||||
}
|
||||
text += &vtype.to_string();
|
||||
}
|
||||
text += ")";
|
||||
write!(f, "{}", text)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RuntimePanic {
|
||||
Fatal,
|
||||
@ -109,4 +135,5 @@ pub enum RuntimePanic {
|
||||
InvalidHeapAddress,
|
||||
ValueNotInitialized,
|
||||
InvalidTypeAssign,
|
||||
InvalidFuncAddress,
|
||||
}
|
||||
|
22
src/main.rs
22
src/main.rs
@ -11,7 +11,7 @@ use std::path::Path;
|
||||
|
||||
use compiler::Compiler;
|
||||
use parser::Parser;
|
||||
use vm::VirtualMachine;
|
||||
use vm::{BuiltinFunctionDef, BuiltinFunctions, Value, VariableType, VirtualMachine};
|
||||
|
||||
fn main() {
|
||||
let path = Path::new("reid_src/test.reid");
|
||||
@ -20,15 +20,29 @@ fn main() {
|
||||
eprintln!("Syntax error: {}", error);
|
||||
std::process::exit(1);
|
||||
}
|
||||
dbg!(&parsed);
|
||||
let compiled = Compiler::from(parsed.unwrap()).compile();
|
||||
//dbg!(&parsed);
|
||||
|
||||
let print = BuiltinFunctionDef::new(
|
||||
"print",
|
||||
vec![VariableType::TypeString],
|
||||
Box::new(move |args| {
|
||||
let Value::StringVal(string) = &args[0];
|
||||
println!("{}", string);
|
||||
}),
|
||||
);
|
||||
let builtin_functions = BuiltinFunctions(vec![print]);
|
||||
|
||||
let compiled = Compiler::from(parsed.unwrap())
|
||||
.with_builtin_functions(builtin_functions.signatures())
|
||||
.compile();
|
||||
if let Err(error) = compiled {
|
||||
eprintln!("Compilation error: {}", error);
|
||||
std::process::exit(1);
|
||||
}
|
||||
dbg!(&compiled);
|
||||
//dbg!(&compiled);
|
||||
|
||||
let mut vm = VirtualMachine::from(compiled.unwrap());
|
||||
vm.add_builtin_functions(builtin_functions);
|
||||
if let Err(error) = vm.run() {
|
||||
eprintln!("Runtime panic: {:#?}", error);
|
||||
std::process::exit(1);
|
||||
|
@ -257,10 +257,6 @@ impl<'a> Expect<'a> {
|
||||
other,
|
||||
)
|
||||
}
|
||||
|
||||
fn get_expect<T: Into<String>>(&mut self, expectable: Expectable<T>) -> Expect {
|
||||
self.parser.expect(expectable)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Expects<'a> {
|
||||
|
@ -74,6 +74,7 @@ impl Expression {
|
||||
Err(SyntaxError::ExpectedToken(parser.pos(), '}'))
|
||||
}
|
||||
} else if let Some(texts) = parser.expect_ident().and(Expectable::Static("(")).get() {
|
||||
let pos = parser.pos();
|
||||
let name = texts.get(0).unwrap();
|
||||
let mut arg_list = Vec::new();
|
||||
while {
|
||||
@ -95,7 +96,6 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
} {}
|
||||
let pos = parser.pos();
|
||||
parser
|
||||
.expect_static(")")
|
||||
.get_or(SyntaxError::ExpectedToken(pos, ')'))?;
|
||||
|
101
src/vm/functions.rs
Normal file
101
src/vm/functions.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use super::{Value, VariableType};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FunctionSignature {
|
||||
pub name: String,
|
||||
pub parameters: Vec<VariableType>,
|
||||
}
|
||||
|
||||
impl FunctionSignature {
|
||||
pub fn new<T: Into<String>>(name: T, params: Vec<VariableType>) -> FunctionSignature {
|
||||
FunctionSignature {
|
||||
name: name.into(),
|
||||
parameters: params,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for FunctionSignature {
|
||||
fn eq(&self, other: &FunctionSignature) -> bool {
|
||||
if self.name == other.name && self.parameters.len() == other.parameters.len() {
|
||||
let mut found_difference = false;
|
||||
for (idx, t) in self.parameters.iter().enumerate() {
|
||||
if other.parameters[idx] != *t {
|
||||
found_difference = true;
|
||||
}
|
||||
}
|
||||
!found_difference
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BuiltinFunctionDef> for FunctionSignature {
|
||||
fn from(from: BuiltinFunctionDef) -> FunctionSignature {
|
||||
from.signature
|
||||
}
|
||||
}
|
||||
|
||||
pub enum FunctionDef {
|
||||
Builtin(BuiltinFunctionDef),
|
||||
}
|
||||
|
||||
impl FunctionDef {
|
||||
fn get_signature(&self) -> &FunctionSignature {
|
||||
match self {
|
||||
FunctionDef::Builtin(func) => &func.signature,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for FunctionDef {
|
||||
fn eq(&self, other: &FunctionDef) -> bool {
|
||||
self.get_signature() == other.get_signature()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<FunctionSignature> for FunctionDef {
|
||||
fn eq(&self, other: &FunctionSignature) -> bool {
|
||||
self.get_signature() == other
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BuiltinFunctionDef {
|
||||
pub signature: FunctionSignature,
|
||||
pub function: Box<dyn Fn(Vec<Value>)>,
|
||||
}
|
||||
|
||||
impl BuiltinFunctionDef {
|
||||
pub fn new<T: Into<String>>(
|
||||
name: T,
|
||||
parameters: Vec<VariableType>,
|
||||
func: Box<dyn Fn(Vec<Value>)>,
|
||||
) -> BuiltinFunctionDef {
|
||||
BuiltinFunctionDef {
|
||||
signature: FunctionSignature {
|
||||
name: name.into(),
|
||||
parameters,
|
||||
},
|
||||
function: func,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BuiltinFunctions(pub Vec<BuiltinFunctionDef>);
|
||||
|
||||
impl BuiltinFunctions {
|
||||
pub fn signatures(&self) -> Vec<FunctionSignature> {
|
||||
let mut signatures = Vec::new();
|
||||
for func in &self.0 {
|
||||
signatures.push(func.signature.clone());
|
||||
}
|
||||
signatures
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BuiltinFunctions> for Vec<BuiltinFunctionDef> {
|
||||
fn from(builtin: BuiltinFunctions) -> Self {
|
||||
builtin.0
|
||||
}
|
||||
}
|
@ -1,14 +1,21 @@
|
||||
pub mod functions;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::fmt::Display;
|
||||
|
||||
use super::compiler::{Command, CompiledReid, HeapID};
|
||||
use super::errors::RuntimePanic;
|
||||
|
||||
pub use functions::*;
|
||||
|
||||
pub struct VirtualMachine {
|
||||
registry_stack: Vec<[Option<Value>; 8]>,
|
||||
registry: [Option<Value>; 8],
|
||||
|
||||
stack: Vec<Value>,
|
||||
heap: HashMap<HeapID, AllocatedVar>,
|
||||
functions: Vec<FunctionDef>,
|
||||
|
||||
position: usize,
|
||||
compiled: CompiledReid,
|
||||
@ -22,12 +29,19 @@ impl VirtualMachine {
|
||||
|
||||
stack: Vec::new(),
|
||||
heap: HashMap::new(),
|
||||
functions: Vec::new(),
|
||||
|
||||
position: 0,
|
||||
compiled,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_builtin_functions<T: Into<Vec<BuiltinFunctionDef>>>(&mut self, list: T) {
|
||||
for func in list.into() {
|
||||
self.functions.push(FunctionDef::Builtin(func));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> Result<(), RuntimePanic> {
|
||||
let mut error = None;
|
||||
while error.is_none() {
|
||||
@ -60,19 +74,19 @@ impl VirtualMachine {
|
||||
match command {
|
||||
Command::InitializeVariable(heapid, vtype) => {
|
||||
self.heap.insert(heapid, AllocatedVar(vtype, None));
|
||||
dbg!("Initialized new variable to heap", &self.heap);
|
||||
//dbg!("Initialized new variable to heap", &self.heap);
|
||||
Ok(())
|
||||
}
|
||||
Command::BeginScope => {
|
||||
self.registry_stack.push(self.registry.clone());
|
||||
self.registry = Default::default();
|
||||
dbg!("Begun new scope");
|
||||
//dbg!("Begun new scope");
|
||||
Ok(())
|
||||
}
|
||||
Command::EndScope => {
|
||||
if let Some(reg) = self.registry_stack.pop() {
|
||||
self.registry = reg;
|
||||
dbg!("Scope ended");
|
||||
//dbg!("Scope ended");
|
||||
Ok(())
|
||||
} else {
|
||||
Err(RuntimePanic::ScopeStackUnderflow)
|
||||
@ -81,7 +95,7 @@ impl VirtualMachine {
|
||||
Command::Pop(regid) => {
|
||||
if let Some(val) = self.stack.pop() {
|
||||
self.registry[regid] = Some(val);
|
||||
dbg!("Registry popped", regid, &self.stack, &self.registry);
|
||||
//dbg!("Registry popped", regid, &self.stack, &self.registry);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(RuntimePanic::StackUnderflow)
|
||||
@ -91,7 +105,7 @@ impl VirtualMachine {
|
||||
if let Some(reg) = &self.registry[regid] {
|
||||
if self.stack.len() < usize::MAX {
|
||||
self.stack.push(reg.clone());
|
||||
dbg!("Registry pushed", regid, &self.stack);
|
||||
//dbg!("Registry pushed", regid, &self.stack);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(RuntimePanic::StackOverflow)
|
||||
@ -104,7 +118,7 @@ impl VirtualMachine {
|
||||
if let Some(reg) = &self.registry[regid] {
|
||||
if let Some(var) = self.heap.get_mut(&heapid) {
|
||||
var.try_set(Some(reg.clone()))?;
|
||||
dbg!("Variable assigned", heapid, regid, &self.heap);
|
||||
//dbg!("Variable assigned", heapid, regid, &self.heap);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(RuntimePanic::InvalidHeapAddress)
|
||||
@ -117,7 +131,7 @@ impl VirtualMachine {
|
||||
if let Some(var) = self.heap.get(&heapid) {
|
||||
if let Some(val) = &var.1 {
|
||||
self.registry[regid] = Some(val.clone());
|
||||
dbg!("Variable pushed to registry", heapid, regid, &self.registry);
|
||||
//dbg!("Variable pushed to registry", heapid, regid, &self.registry);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(RuntimePanic::ValueNotInitialized)
|
||||
@ -129,12 +143,32 @@ impl VirtualMachine {
|
||||
Command::StringLit(string) => {
|
||||
if self.stack.len() < usize::MAX {
|
||||
self.stack.push(Value::StringVal(string.clone()));
|
||||
dbg!("String literal added to stack", string, &self.stack);
|
||||
//dbg!("String literal added to stack", string, &self.stack);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(RuntimePanic::StackOverflow)
|
||||
}
|
||||
}
|
||||
Command::FunctionCall(funcid) => {
|
||||
if self.functions.len() <= funcid {
|
||||
Err(RuntimePanic::InvalidFuncAddress)
|
||||
} else {
|
||||
match &self.functions[funcid] {
|
||||
FunctionDef::Builtin(f) => {
|
||||
let mut params = Vec::new();
|
||||
for _ in 0..f.signature.parameters.len() {
|
||||
if let Some(val) = self.stack.pop() {
|
||||
params.push(val);
|
||||
} else {
|
||||
return Err(RuntimePanic::StackUnderflow);
|
||||
}
|
||||
}
|
||||
(f.function)(params);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -157,14 +191,8 @@ impl AllocatedVar {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum VariableType {
|
||||
TypeString,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
enum Value {
|
||||
pub enum Value {
|
||||
StringVal(String),
|
||||
}
|
||||
|
||||
@ -175,3 +203,16 @@ impl Value {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum VariableType {
|
||||
TypeString,
|
||||
}
|
||||
|
||||
impl ToString for VariableType {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
VariableType::TypeString => "String".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user