Commit 683a3740 authored by Stephen D's avatar Stephen D
Browse files

Merge branch 'ci' into 'master'

CI

See merge request !2
parents 4c0f57d2 c394d810
Pipeline #36 passed with stage
in 12 minutes and 41 seconds
image: "rust:latest"
before_script:
- rustup component add rustfmt
- rustup component add clippy
- cargo install cargo-deb
test:
script:
- cargo fmt -- --check
- cargo clippy --all-targets --all-features -- -D warnings
- cargo test
build:
script:
- cargo build
......@@ -784,7 +784,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xbasic"
version = "0.3.1"
version = "0.3.2"
dependencies = [
"criterion",
"num-derive",
......
[package]
name = "xbasic"
description = "A library that allows adding a scripting language onto your project with ease. This lets your users write their own arbitrary logic."
version = "0.3.1"
version = "0.3.2"
authors = ["Stephen <stephen@stephendownward.ca>"]
edition = "2018"
readme = "README.md"
......
use std::fmt;
/// Represents an error when defining a custom xBASIC function
#[derive(Debug, PartialEq)]
pub enum DefineFunctionError {
NameInUse,
FunctionLimitReached,
}
impl fmt::Display for DefineFunctionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DefineFunctionError::NameInUse => write!(f, "Function name is already in use"),
DefineFunctionError::FunctionLimitReached => write!(
f,
"The maximum number of functions have already been defined"
),
}
}
}
impl std::error::Error for DefineFunctionError {}
/// Represents an error when running some xBASIC code
#[derive(Debug, PartialEq)]
pub enum RunError {
Scan,
ResolveFunctions,
Parse,
Compile,
Runtime,
}
impl fmt::Display for RunError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use RunError::*;
match self {
Scan => write!(f, "Could not scan code"),
ResolveFunctions => write!(f, "Could not resolve functions"),
Parse => write!(f, "Could not parse into tokens"),
Compile => write!(f, "Could not compile tokens into bytecode"),
Runtime => write!(f, "Could not execute bytecode"),
}
}
}
impl std::error::Error for RunError {}
/// Represents an error when calling an xBASIC function from Rust
#[derive(Debug, PartialEq)]
pub enum CallFunctionError {
ArityMismatch,
Runtime,
NotFound,
}
impl fmt::Display for CallFunctionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use CallFunctionError::*;
match self {
ArityMismatch => write!(f, "Provided the wrong number of arguments"),
Runtime => write!(f, "Could not execute bytecode"),
NotFound => write!(f, "Could not find function by name"),
}
}
}
impl std::error::Error for CallFunctionError {}
pub mod basic_io;
mod chunk;
mod compiler;
pub mod error;
mod error_handler;
pub mod expr;
mod function;
......
......@@ -70,9 +70,9 @@ pub struct Token {
impl Token {
pub fn new(token_type: TokenType, lexeme: String, line: usize) -> Self {
Self {
token_type,
lexeme,
line,
lexeme,
token_type,
}
}
}
......@@ -16,8 +16,8 @@ impl CallFrame {
fn new(chunk_id: usize, ip: usize, offset: usize) -> Self {
Self {
chunk_id,
ip,
offset,
ip,
}
}
}
......@@ -444,7 +444,7 @@ where
}
fn write_exprvalue(&mut self, value: ExprValue) {
if self.buffer != "" {
if !self.buffer.is_empty() {
self.buffer += " "
}
self.buffer += &value.into_string();
......
use crate::basic_io::BasicIO;
use crate::chunk::Chunk;
use crate::compiler::Compiler;
use crate::error::*;
use crate::error_handler::ErrorHandler;
use crate::expr::ExprValue;
use crate::function::{Function, FunctionDefinition, FunctionType};
......@@ -56,21 +57,21 @@ where
name: String,
arity: u8,
function: F,
) -> Result<(), ()>
) -> Result<(), DefineFunctionError>
where
F: Fn(Vec<ExprValue>, &mut T) -> ExprValue,
{
if self.native_functions.len() < 256 {
// Prevent defining the same native function twice
if self.native_functions.contains_key(&name) {
return Err(());
return Err(DefineFunctionError::NameInUse);
}
self.native_functions
.insert(name.clone(), NativeFunction::new(name, arity, function));
Ok(())
} else {
Err(())
Err(DefineFunctionError::FunctionLimitReached)
}
}
......@@ -128,13 +129,13 @@ where
/// # Arguments
///
/// * source - The XBasic code. This should be terminated by a newline character.
pub fn run(&mut self, source: &str) -> Result<(), ()> {
pub fn run(&mut self, source: &str) -> Result<(), RunError> {
let mut sc = Scanner::new(source, &mut self.error_handler);
let tokens = sc.scan_tokens();
let tokens = match tokens {
Ok(x) => x,
Err(_) => return Err(()),
Err(_) => return Err(RunError::Scan),
};
// If a program consists of only newlines and an Eof, we shouldn't run it
......@@ -159,7 +160,7 @@ where
.collect::<Vec<_>>(),
) {
Some(x) => x,
None => return Err(()),
None => return Err(RunError::ResolveFunctions),
}
};
......@@ -192,7 +193,7 @@ where
}
stmts
}
None => return Err(()),
None => return Err(RunError::Parse),
};
let native_function_ids: HashMap<String, usize> = self
......@@ -219,11 +220,11 @@ where
&mut self.error_handler,
);
}
None => return Err(()),
None => return Err(RunError::Compile),
}
if self.error_handler.had_runtime_error {
return Err(());
return Err(RunError::Runtime);
}
Ok(())
......@@ -241,12 +242,15 @@ where
///
/// * name - The name of the function to call
/// * arguments - The arguments of the function to be called
pub fn call_function(&mut self, name: &str, arguments: &[ExprValue]) -> Result<ExprValue, ()> {
pub fn call_function(
&mut self,
name: &str,
arguments: &[ExprValue],
) -> Result<ExprValue, CallFunctionError> {
for (i, function) in self.functions.iter().enumerate() {
if function.name == name {
if function.parameters.len() != arguments.len() {
// Arity mismatch
return Err(());
return Err(CallFunctionError::ArityMismatch);
}
// Generate instructions for function call
let mut instructions = Vec::new();
......@@ -275,14 +279,15 @@ where
.collect(),
&mut self.error_handler,
) {
return Err(());
return Err(CallFunctionError::Runtime);
}
// Pop the return value
return Ok(self.vm.pop());
}
}
Err(())
Err(CallFunctionError::NotFound)
}
/// Gets a reference to the IO object.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment