Add functions and a print function

This commit is contained in:
Sofia 2020-06-24 21:58:16 +03:00
parent 86c2b13d1a
commit 8b60677123
8 changed files with 261 additions and 28 deletions

View File

@ -1 +1,3 @@
print();
let otus = "Hello, world!";
let dotus = otus;
print(dotus);

View File

@ -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,

View File

@ -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,
}

View File

@ -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);

View File

@ -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> {

View File

@ -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
View 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
}
}

View File

@ -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(),
}
}
}