Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 78 additions & 1 deletion bytecode/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,83 @@ pub mod implementations {
}
}

instruction! {
unwrap_into(ctx, args) {
let Some(name) = args.first() else {
bail!("`unwrap_into` requires a name");
};

let Some(primitive) = ctx.pop() else {
bail!("`unwrap_into` requires a primitive at the top of the local operating stack");
};

let status = match primitive {
Primitive::Optional(Some(unwrapped)) => {
let var = unwrapped.as_ref().to_owned();

let var = unsafe { var.move_out_of_heap_primitive() };

ctx.register_variable_local(name.to_owned(), var)?;
true
}
primitive @ Primitive::Optional(None) => {
let primitive = unsafe { primitive.move_out_of_heap_primitive() };

ctx.register_variable_local(name.to_owned(), primitive)?;
false
},
other_primitive => {
let other_primitive = unsafe { other_primitive.move_out_of_heap_primitive() };

ctx.register_variable_local(name.to_owned(), other_primitive)?;
true
}
};

ctx.push(bool!(status));

Ok(())
}

unwrap(ctx, args) {
let Some(primitive) = ctx.get_last_op_item_mut() else {
bail!("`unwrap` requires a primitive at the top of the local operating stack");
};

if let Primitive::Optional(optional) = primitive {
if let Some(new_primitive) = optional {
*primitive = *new_primitive.clone();
} else {
let span = args.get(0).map(String::as_str);
bail!("LOGIC ERROR IN CODE >> {} >> unwrap of `nil`", span.unwrap_or("<no details>"));
}
}

Ok(())
}

jmp_not_nil(ctx, args) {
let Some(primitive) = ctx.get_last_op_item_mut() else {
bail!("`jmp_not_nil` requires a primitive at the top of the local operating stack");
};

let Some(lines_to_jump) = args.get(0) else {
bail!("`jmp_not_nil` requires lines_to_jump");
};

let lines_to_jump = lines_to_jump.parse::<isize>().context("jmp_not_nil needs lines_to_jump: isize")?;

if let Primitive::Optional(None) = primitive {
ctx.pop();
return Ok(())
}

ctx.signal(InstructionExitState::Goto(lines_to_jump));

Ok(())
}
}

instruction! {
store(ctx, args) {
let Some(name) = args.first() else {
Expand Down Expand Up @@ -1017,7 +1094,7 @@ pub mod implementations {

let primitive = ctx.pop().unwrap();

let result: Rc<RefCell<(Primitive, VariableFlags)>> = primitive.lookup(name).with_context(|| format!("{name} does not exist on {primitive:?}"))?;
let result: Rc<RefCell<(Primitive, VariableFlags)>> = primitive.lookup(name).with_context(|| format!("`{name}` does not exist on `{primitive:?}`"))?;

// println!("LOOKING UP ON: {primitive:?}\nLOOKUP RETURNED: {result:?}");

Expand Down
11 changes: 10 additions & 1 deletion bytecode/src/instruction_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub static REPR_TO_BIN: Lazy<HashMap<&[u8], u8>> = Lazy::new(|| {
///
/// Saving this as a constant makes it harder for the arrays to fall out of sync
/// by requiring that they both take the same size.
pub const INSTRUCTION_COUNT: usize = 62;
pub const INSTRUCTION_COUNT: usize = 65;

/// This is an array that provides O(1) lookups of names from bytes.
pub static BIN_TO_REPR: [&[u8]; INSTRUCTION_COUNT] = [
Expand Down Expand Up @@ -88,6 +88,9 @@ pub static BIN_TO_REPR: [&[u8]; INSTRUCTION_COUNT] = [
/* 0x3B [59] */ b"export_name",
/* 0x3C [60] */ b"export_special",
/* 0x3D [61] */ b"load_self_export",
/* 0x3E [62] */ b"unwrap_into",
/* 0x3F [63] */ b"unwrap",
/* 0x40 [64] */ b"jmp_not_nil",
];

/// Similar to [`BIN_TO_REPR`][crate::instruction_constants::BIN_TO_REPR],
Expand Down Expand Up @@ -155,6 +158,9 @@ pub static FUNCTION_POINTER_LOOKUP: [InstructionSignature; INSTRUCTION_COUNT] =
implementations::export_name,
implementations::export_special,
implementations::load_self_export,
implementations::unwrap_into,
implementations::unwrap,
implementations::jmp_not_nil,
];

pub mod id {
Expand Down Expand Up @@ -223,4 +229,7 @@ pub mod id {
pub const EXPORT_NAME: u8 = 59;
pub const EXPORT_SELF: u8 = 60;
pub const LOAD_SELF_EXPORT: u8 = 61;
pub const UNWRAP_INTO: u8 = 62;
pub const UNWRAP: u8 = 63;
pub const JMP_NOT_NIL: u8 = 64;
}
12 changes: 10 additions & 2 deletions bytecode/src/variables/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,20 @@ impl Primitive {
};
}

use Primitive as P;

if let (P::Optional(maybe), yes) | (yes, P::Optional(maybe)) = (self, rhs) {
if let Some(maybe_unwrapped) = maybe {
return Ok(maybe_unwrapped.as_ref() == yes);
};
}

impl_eq!(Int with Float(r=f64), BigInt(r=i128), Byte(r=i32));
impl_eq!(Float with Int(r=f64), BigInt(r=f64), Byte(r=f64));
impl_eq!(BigInt with Float(r=f64), Int(r=i128), Byte(r=i128));
impl_eq!(Byte with Float(r=f64), BigInt(r=i128), Int(r=i32));

impl_eq!(each Str, Bool with itself);
impl_eq!(each Optional, Str, Bool with itself);
}

/// Returns whether this primitive is numeric.
Expand Down Expand Up @@ -349,7 +357,7 @@ impl Primitive {
}
Object(o) => write!(f, "{}", o.borrow()),
Optional(Some(primitive)) => write!(f, "{primitive}"),
Optional(None) => write!(f, "none"),
Optional(None) => write!(f, "nil"),
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod loop_control_flow;
mod math_expr;
mod number;
mod number_loop;
mod optionals;
mod print_statement;
mod reassignment;
mod r#return;
Expand All @@ -41,6 +42,7 @@ pub(crate) use loop_control_flow::{Break, Continue};
pub(crate) use math_expr::{Expr, Op as BinaryOperation};
pub(crate) use number::Number;
pub(crate) use number_loop::NumberLoop;
pub(crate) use optionals::{Unwrap, UnwrapExpr};
pub(crate) use print_statement::PrintStatement;
pub(crate) use r#return::ReturnStatement;
pub(crate) use r#type::TypeLayout;
Expand Down
14 changes: 1 addition & 13 deletions compiler/src/ast/assignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,21 +149,9 @@ impl Compile for Assignment {
let mut value_init = if let ConstexprEvaluation::Owned(value) = maybe_constexpr_eval {
value.compile(state)?
} else {
match &self.value() {
Value::Ident(ident) => ident.compile(state)?,
Value::Function(function) => function.in_place_compile_for_value(state)?,
Value::Number(number) => number.compile(state)?,
Value::String(string) => string.compile(state)?,
Value::MathExpr(math_expr) => math_expr.compile(state)?,
Value::Boolean(boolean) => boolean.compile(state)?,
Value::List(list) => list.compile(state)?,
}
self.value().compile(state)?
};

// if let Some(ref next) = &self.value {
// value_init.append(&mut next.compile(function_buffer)?);
// }

match self {
Self::Single { ident, .. } => {
let name = ident.name();
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/ast/assignment/assignment_no_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl Parser {
input.as_span(),
&input.user_data().get_source_file_name(),
"could not get the type".into(),
|| vec!["could not infer the type of the value\ntry explicitly defining a type: `name: type = ...`"],
|| vec!["Could not infer the type of the value; try explicitly defining a type"],
)
.to_err_vec()?;

Expand Down
10 changes: 5 additions & 5 deletions compiler/src/ast/assignment/assignment_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ impl Parser {
let value: Value = Self::value(value)?;

if let Ok(ref assignment_ty) = value.for_type() {
if !ty
.as_ref()
.get_type_recursively()
.eq_complex(assignment_ty.get_type_recursively(), self_type.as_ref())
{
if !ty.as_ref().get_type_recursively().eq_complex(
assignment_ty.get_type_recursively(),
self_type.as_ref(),
false,
) {
let hint = ty.get_error_hint_between_types(assignment_ty).map_or_else(
|| Cow::Borrowed(""),
|str| Cow::Owned(format!("\n\t- hint: {str}")),
Expand Down
23 changes: 21 additions & 2 deletions compiler/src/ast/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
use super::{
class::Class, Assertion, Assignment, Break, CompilationState, Compile, CompiledItem, Continue,
Dependencies, Dependency, Expr, IfStatement, NumberLoop, PrintStatement, Reassignment,
ReturnStatement, WhileLoop,
ReturnStatement, Unwrap, UnwrapExpr, WhileLoop,
};

#[derive(Debug)]
Expand All @@ -28,6 +28,8 @@ pub(crate) enum Declaration {
Break(Break),
Assertion(Assertion),
Class(Class),
UnwrapExpr(UnwrapExpr),
ValueUnwrap(Unwrap),
}

impl Dependencies for Declaration {
Expand All @@ -42,7 +44,10 @@ impl Dependencies for Declaration {
Self::NumberLoop(number_loop) => number_loop.supplies(),
Self::Assertion(assertion) => assertion.supplies(),
Self::Class(class) => class.supplies(),
Self::Reassignment(_) | Self::Continue(_) | Self::Break(_) => vec![],
Self::UnwrapExpr(unwrap_expr) => unwrap_expr.supplies(),
Self::ValueUnwrap(value_unwrap) => value_unwrap.supplies(),
Self::Reassignment(reassignment) => reassignment.supplies(),
Self::Continue(_) | Self::Break(_) => vec![],
}
}

Expand All @@ -58,6 +63,8 @@ impl Dependencies for Declaration {
Self::Reassignment(reassignment) => reassignment.net_dependencies(),
Self::Assertion(assertion) => assertion.net_dependencies(),
Self::Class(class) => class.net_dependencies(),
Self::UnwrapExpr(unwrap_expr) => unwrap_expr.net_dependencies(),
Self::ValueUnwrap(value_unwrap) => value_unwrap.net_dependencies(),
Self::Continue(_) | Self::Break(_) => vec![],
}
}
Expand All @@ -82,6 +89,16 @@ impl Compile for Declaration {
Self::NumberLoop(x) => x.compile(state),
Self::Assertion(x) => x.compile(state),
Self::Class(x) => x.compile(state),
Self::UnwrapExpr(x) => {
let mut unwrap_expr_compiled = x.compile(state)?;
unwrap_expr_compiled.push(instruction!(void));
Ok(unwrap_expr_compiled)
}
Self::ValueUnwrap(x) => {
let mut unwrap_compiled = x.compile(state)?;
unwrap_compiled.push(instruction!(void));
Ok(unwrap_compiled)
}
}
}
}
Expand Down Expand Up @@ -111,6 +128,8 @@ impl Parser {
Rule::reassignment => Declaration::Reassignment(Self::reassignment(declaration)?),
Rule::assertion => Declaration::Assertion(Self::assertion(declaration)?),
Rule::class => Declaration::Class(Self::class(declaration)?),
Rule::unwrap_expr => Declaration::UnwrapExpr(Self::unwrap_expr(declaration)?),
Rule::value_unwrap => Declaration::ValueUnwrap(Self::unwrap(declaration)?),
x => unreachable!("{x:?} is not supported"),
};

Expand Down
17 changes: 12 additions & 5 deletions compiler/src/ast/function_arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ impl Parser {
let children = input.children();

let mut result = vec![];
let mut result_len: usize = 0;
let mut errors = vec![];

let expected_types: Cow<Vec<Cow<TypeLayout>>> = expected_parameters.to_types();
Expand All @@ -53,11 +54,17 @@ impl Parser {

let user_gave = arg_ty.get_type_recursively();

let class_self_case = allow_self_type
.map(|ty| expected_ty_at_idx.is_class_self() && ty.eq(user_gave))
.unwrap_or(false);
let maybe_class_type = allow_self_type.map(|x| {
let TypeLayout::Class(class_type) = x else {
unreachable!();
};

if !user_gave.eq(expected_ty_at_idx) && !class_self_case {
class_type
});

result_len += 1;

if !expected_ty_at_idx.eq_complex(user_gave, maybe_class_type, false) {
let argument_number = idx + 1;
let error_message = format!("type mismatch when calling function (argument #{argument_number} was expected to be `{expected_ty_at_idx}` based on type signature, instead found `{user_gave}`)");
errors.push(new_err(
Expand All @@ -72,7 +79,7 @@ impl Parser {
result.push(value_for_arg)
}

let result_len = result.len();
// let result_len = result.len();
let expected_parameters_len = expected_parameters.len();

if result_len != expected_parameters_len {
Expand Down
20 changes: 10 additions & 10 deletions compiler/src/ast/if_statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,16 @@ impl Parser {
let body = children.next().expect("no body");
let else_statement = children.next();

let child_returns_type = input
.user_data()
.return_statement_expected_yield_type()
.map_or_else(
|| ScopeReturnStatus::No,
|ty| ScopeReturnStatus::ParentShould(ty.clone()),
);

let if_scope: ScopeHandle = input.user_data().push_if_typed(child_returns_type);

let condition_as_value = Self::value(condition)?;

let condition_type = condition_as_value.for_type().to_err_vec()?;
Expand All @@ -148,16 +158,6 @@ impl Parser {

let can_determine_is_if_branch_truthy = false; // TODO

let child_returns_type = input
.user_data()
.return_statement_expected_yield_type()
.map_or_else(
|| ScopeReturnStatus::No,
|ty| ScopeReturnStatus::ParentShould(ty.clone()),
);

let if_scope: ScopeHandle = input.user_data().push_if_typed(child_returns_type);

let body_as_block = Self::block(body);

// get the return type back
Expand Down
Loading