Bind all unary, binary and constants to KCL (#1781)
This commit is contained in:
		@ -2,13 +2,16 @@ use std::collections::HashMap;
 | 
			
		||||
 | 
			
		||||
use kcl_lib::ast::types::{LiteralIdentifier, LiteralValue};
 | 
			
		||||
 | 
			
		||||
use kittycad_execution_plan::constants;
 | 
			
		||||
use kittycad_execution_plan_traits::Primitive;
 | 
			
		||||
 | 
			
		||||
use super::{native_functions, Address};
 | 
			
		||||
use crate::{CompileError, KclFunction};
 | 
			
		||||
 | 
			
		||||
/// KCL values which can be written to KCEP memory.
 | 
			
		||||
/// This is recursive. For example, the bound value might be an array, which itself contains bound values.
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
#[cfg_attr(test, derive(Eq, PartialEq))]
 | 
			
		||||
#[cfg_attr(test, derive(PartialEq))]
 | 
			
		||||
pub enum EpBinding {
 | 
			
		||||
    /// A KCL value which gets stored in a particular address in KCEP memory.
 | 
			
		||||
    Single(Address),
 | 
			
		||||
@ -23,6 +26,8 @@ pub enum EpBinding {
 | 
			
		||||
        properties: HashMap<String, EpBinding>,
 | 
			
		||||
    },
 | 
			
		||||
    /// Not associated with a KCEP address.
 | 
			
		||||
    Constant(Primitive),
 | 
			
		||||
    /// Not associated with a KCEP address.
 | 
			
		||||
    Function(KclFunction),
 | 
			
		||||
    /// SketchGroups have their own storage.
 | 
			
		||||
    SketchGroup { index: usize },
 | 
			
		||||
@ -52,11 +57,13 @@ impl EpBinding {
 | 
			
		||||
                    EpBinding::SketchGroup { .. } => Err(CompileError::CannotIndex),
 | 
			
		||||
                    EpBinding::Single(_) => Err(CompileError::CannotIndex),
 | 
			
		||||
                    EpBinding::Function(_) => Err(CompileError::CannotIndex),
 | 
			
		||||
                    EpBinding::Constant(_) => Err(CompileError::CannotIndex),
 | 
			
		||||
                },
 | 
			
		||||
                // Objects can be indexed by string properties.
 | 
			
		||||
                LiteralValue::String(property) => match self {
 | 
			
		||||
                    EpBinding::Single(_) => Err(CompileError::NoProperties),
 | 
			
		||||
                    EpBinding::Function(_) => Err(CompileError::NoProperties),
 | 
			
		||||
                    EpBinding::Constant(_) => Err(CompileError::CannotIndex),
 | 
			
		||||
                    EpBinding::SketchGroup { .. } => Err(CompileError::NoProperties),
 | 
			
		||||
                    EpBinding::Sequence { .. } => Err(CompileError::ArrayDoesNotHaveProperties),
 | 
			
		||||
                    EpBinding::Map {
 | 
			
		||||
@ -103,8 +110,58 @@ impl BindingScope {
 | 
			
		||||
            // TODO: Actually put the stdlib prelude in here,
 | 
			
		||||
            // things like `startSketchAt` and `line`.
 | 
			
		||||
            ep_bindings: HashMap::from([
 | 
			
		||||
                ("E".into(), EpBinding::Constant(constants::E)),
 | 
			
		||||
                ("PI".into(), EpBinding::Constant(constants::PI)),
 | 
			
		||||
                ("id".into(), EpBinding::from(KclFunction::Id(native_functions::Id))),
 | 
			
		||||
                ("abs".into(), EpBinding::from(KclFunction::Abs(native_functions::Abs))),
 | 
			
		||||
                (
 | 
			
		||||
                    "acos".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::Acos(native_functions::Acos)),
 | 
			
		||||
                ),
 | 
			
		||||
                (
 | 
			
		||||
                    "asin".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::Asin(native_functions::Asin)),
 | 
			
		||||
                ),
 | 
			
		||||
                (
 | 
			
		||||
                    "atan".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::Atan(native_functions::Atan)),
 | 
			
		||||
                ),
 | 
			
		||||
                (
 | 
			
		||||
                    "ceil".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::Ceil(native_functions::Ceil)),
 | 
			
		||||
                ),
 | 
			
		||||
                ("cos".into(), EpBinding::from(KclFunction::Cos(native_functions::Cos))),
 | 
			
		||||
                (
 | 
			
		||||
                    "floor".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::Floor(native_functions::Floor)),
 | 
			
		||||
                ),
 | 
			
		||||
                ("ln".into(), EpBinding::from(KclFunction::Ln(native_functions::Ln))),
 | 
			
		||||
                (
 | 
			
		||||
                    "log10".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::Log10(native_functions::Log10)),
 | 
			
		||||
                ),
 | 
			
		||||
                (
 | 
			
		||||
                    "log2".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::Log2(native_functions::Log2)),
 | 
			
		||||
                ),
 | 
			
		||||
                ("sin".into(), EpBinding::from(KclFunction::Sin(native_functions::Sin))),
 | 
			
		||||
                (
 | 
			
		||||
                    "sqrt".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::Sqrt(native_functions::Sqrt)),
 | 
			
		||||
                ),
 | 
			
		||||
                ("tan".into(), EpBinding::from(KclFunction::Tan(native_functions::Tan))),
 | 
			
		||||
                (
 | 
			
		||||
                    "toDegrees".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::ToDegrees(native_functions::ToDegrees)),
 | 
			
		||||
                ),
 | 
			
		||||
                (
 | 
			
		||||
                    "toRadians".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::ToRadians(native_functions::ToRadians)),
 | 
			
		||||
                ),
 | 
			
		||||
                ("add".into(), EpBinding::from(KclFunction::Add(native_functions::Add))),
 | 
			
		||||
                ("log".into(), EpBinding::from(KclFunction::Log(native_functions::Log))),
 | 
			
		||||
                ("max".into(), EpBinding::from(KclFunction::Max(native_functions::Max))),
 | 
			
		||||
                ("min".into(), EpBinding::from(KclFunction::Min(native_functions::Min))),
 | 
			
		||||
                (
 | 
			
		||||
                    "startSketchAt".into(),
 | 
			
		||||
                    EpBinding::from(KclFunction::StartSketchAt(native_functions::sketch::StartSketchAt)),
 | 
			
		||||
 | 
			
		||||
@ -259,6 +259,24 @@ impl Planner {
 | 
			
		||||
                    binding,
 | 
			
		||||
                } = match callee {
 | 
			
		||||
                    KclFunction::Id(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Abs(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Acos(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Asin(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Atan(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Ceil(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Cos(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Floor(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Ln(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Log10(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Log2(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Sin(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Sqrt(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Tan(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::ToDegrees(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::ToRadians(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Log(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Max(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Min(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::StartSketchAt(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::Extrude(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
                    KclFunction::LineTo(f) => f.call(&mut ctx, args)?,
 | 
			
		||||
@ -634,6 +652,21 @@ impl Eq for UserDefinedFunction {}
 | 
			
		||||
#[cfg_attr(test, derive(Eq, PartialEq))]
 | 
			
		||||
enum KclFunction {
 | 
			
		||||
    Id(native_functions::Id),
 | 
			
		||||
    Abs(native_functions::Abs),
 | 
			
		||||
    Acos(native_functions::Acos),
 | 
			
		||||
    Asin(native_functions::Asin),
 | 
			
		||||
    Atan(native_functions::Atan),
 | 
			
		||||
    Ceil(native_functions::Ceil),
 | 
			
		||||
    Cos(native_functions::Cos),
 | 
			
		||||
    Floor(native_functions::Floor),
 | 
			
		||||
    Ln(native_functions::Ln),
 | 
			
		||||
    Log10(native_functions::Log10),
 | 
			
		||||
    Log2(native_functions::Log2),
 | 
			
		||||
    Sin(native_functions::Sin),
 | 
			
		||||
    Sqrt(native_functions::Sqrt),
 | 
			
		||||
    Tan(native_functions::Tan),
 | 
			
		||||
    ToDegrees(native_functions::ToDegrees),
 | 
			
		||||
    ToRadians(native_functions::ToRadians),
 | 
			
		||||
    StartSketchAt(native_functions::sketch::StartSketchAt),
 | 
			
		||||
    LineTo(native_functions::sketch::LineTo),
 | 
			
		||||
    Line(native_functions::sketch::Line),
 | 
			
		||||
@ -642,6 +675,9 @@ enum KclFunction {
 | 
			
		||||
    YLineTo(native_functions::sketch::YLineTo),
 | 
			
		||||
    YLine(native_functions::sketch::YLine),
 | 
			
		||||
    Add(native_functions::Add),
 | 
			
		||||
    Log(native_functions::Log),
 | 
			
		||||
    Max(native_functions::Max),
 | 
			
		||||
    Min(native_functions::Min),
 | 
			
		||||
    UserDefined(UserDefinedFunction),
 | 
			
		||||
    Extrude(native_functions::sketch::Extrude),
 | 
			
		||||
    Close(native_functions::sketch::Close),
 | 
			
		||||
 | 
			
		||||
@ -2,18 +2,15 @@
 | 
			
		||||
//! This includes some of the stdlib, e.g. `startSketchAt`.
 | 
			
		||||
//! But some other stdlib functions will be written in KCL.
 | 
			
		||||
 | 
			
		||||
use kittycad_execution_plan::{BinaryArithmetic, Destination, Instruction};
 | 
			
		||||
use kittycad_execution_plan::{
 | 
			
		||||
    BinaryArithmetic, BinaryOperation, Destination, Instruction, Operand, UnaryArithmetic, UnaryOperation,
 | 
			
		||||
};
 | 
			
		||||
use kittycad_execution_plan_traits::Address;
 | 
			
		||||
 | 
			
		||||
use crate::{CompileError, EpBinding, EvalPlan};
 | 
			
		||||
 | 
			
		||||
pub mod sketch;
 | 
			
		||||
 | 
			
		||||
/// The identity function. Always returns its first input.
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
#[cfg_attr(test, derive(Eq, PartialEq))]
 | 
			
		||||
pub struct Id;
 | 
			
		||||
 | 
			
		||||
pub trait Callable {
 | 
			
		||||
    fn call(&self, ctx: &mut Context<'_>, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError>;
 | 
			
		||||
}
 | 
			
		||||
@ -32,6 +29,65 @@ impl<'a> Context<'a> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Unary operator macro to quickly create new bindings.
 | 
			
		||||
macro_rules! define_unary {
 | 
			
		||||
  () => {};
 | 
			
		||||
  ($h:ident$( $r:ident)*) => {
 | 
			
		||||
    #[derive(Debug, Clone)]
 | 
			
		||||
    #[cfg_attr(test, derive(Eq, PartialEq))]
 | 
			
		||||
    pub struct $h;
 | 
			
		||||
 | 
			
		||||
    impl Callable for $h {
 | 
			
		||||
        fn call(&self, ctx: &mut Context<'_>, mut args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
 | 
			
		||||
            if args.len() > 1 {
 | 
			
		||||
                return Err(CompileError::TooManyArgs {
 | 
			
		||||
                    fn_name: "$h".into(),
 | 
			
		||||
                    maximum: 1,
 | 
			
		||||
                    actual: args.len(),
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let not_enough_args = CompileError::NotEnoughArgs {
 | 
			
		||||
                fn_name: "$h".into(),
 | 
			
		||||
                required: 1,
 | 
			
		||||
                actual: args.len(),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let EpBinding::Single(arg0) = args.pop().ok_or(not_enough_args.clone())? else {
 | 
			
		||||
                return Err(CompileError::InvalidOperand("A single value binding is expected"));
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let destination = ctx.next_address.offset_by(1);
 | 
			
		||||
            let instructions = vec![
 | 
			
		||||
              Instruction::UnaryArithmetic {
 | 
			
		||||
                arithmetic: UnaryArithmetic {
 | 
			
		||||
                  operation: UnaryOperation::$h,
 | 
			
		||||
                  operand: Operand::Reference(arg0)
 | 
			
		||||
                },
 | 
			
		||||
                destination: Destination::Address(destination)
 | 
			
		||||
              }
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            Ok(EvalPlan {
 | 
			
		||||
                instructions,
 | 
			
		||||
                binding: EpBinding::Single(destination),
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    define_unary!($($r)*);
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
define_unary!(Abs Acos Asin Atan Ceil Cos Floor Ln Log10 Log2 Sin Sqrt Tan ToDegrees ToRadians);
 | 
			
		||||
 | 
			
		||||
/// The identity function. Always returns its first input.
 | 
			
		||||
/// Implemented purely on the KCL side so it doesn't need to be in the
 | 
			
		||||
/// define_unary! macro above.
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
#[cfg_attr(test, derive(Eq, PartialEq))]
 | 
			
		||||
pub struct Id;
 | 
			
		||||
 | 
			
		||||
impl Callable for Id {
 | 
			
		||||
    fn call(&self, _: &mut Context<'_>, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
 | 
			
		||||
        if args.len() > 1 {
 | 
			
		||||
@ -56,44 +112,53 @@ impl Callable for Id {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A test function that adds two numbers.
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
#[cfg_attr(test, derive(Eq, PartialEq))]
 | 
			
		||||
pub struct Add;
 | 
			
		||||
/// Binary operator macro to quickly create new bindings.
 | 
			
		||||
macro_rules! define_binary {
 | 
			
		||||
  () => {};
 | 
			
		||||
  ($h:ident$( $r:ident)*) => {
 | 
			
		||||
    #[derive(Debug, Clone)]
 | 
			
		||||
    #[cfg_attr(test, derive(Eq, PartialEq))]
 | 
			
		||||
    pub struct $h;
 | 
			
		||||
 | 
			
		||||
impl Callable for Add {
 | 
			
		||||
    fn call(&self, ctx: &mut Context<'_>, mut args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
 | 
			
		||||
        let len = args.len();
 | 
			
		||||
        if len > 2 {
 | 
			
		||||
            return Err(CompileError::TooManyArgs {
 | 
			
		||||
                fn_name: "add".into(),
 | 
			
		||||
                maximum: 2,
 | 
			
		||||
                actual: len,
 | 
			
		||||
            });
 | 
			
		||||
    impl Callable for $h {
 | 
			
		||||
        fn call(&self, ctx: &mut Context<'_>, mut args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
 | 
			
		||||
          let len = args.len();
 | 
			
		||||
          if len > 2 {
 | 
			
		||||
              return Err(CompileError::TooManyArgs {
 | 
			
		||||
                  fn_name: "$h".into(),
 | 
			
		||||
                  maximum: 2,
 | 
			
		||||
                  actual: len,
 | 
			
		||||
              });
 | 
			
		||||
          }
 | 
			
		||||
          let not_enough_args = CompileError::NotEnoughArgs {
 | 
			
		||||
              fn_name: "$h".into(),
 | 
			
		||||
              required: 2,
 | 
			
		||||
              actual: len,
 | 
			
		||||
          };
 | 
			
		||||
          const ERR: &str = "cannot use composite values (e.g. array) as arguments to $h";
 | 
			
		||||
          let EpBinding::Single(arg1) = args.pop().ok_or(not_enough_args.clone())? else {
 | 
			
		||||
              return Err(CompileError::InvalidOperand(ERR));
 | 
			
		||||
          };
 | 
			
		||||
          let EpBinding::Single(arg0) = args.pop().ok_or(not_enough_args)? else {
 | 
			
		||||
              return Err(CompileError::InvalidOperand(ERR));
 | 
			
		||||
          };
 | 
			
		||||
          let destination = ctx.next_address.offset_by(1);
 | 
			
		||||
          Ok(EvalPlan {
 | 
			
		||||
              instructions: vec![Instruction::BinaryArithmetic {
 | 
			
		||||
                  arithmetic: BinaryArithmetic {
 | 
			
		||||
                      operation: BinaryOperation::$h,
 | 
			
		||||
                      operand0: Operand::Reference(arg0),
 | 
			
		||||
                      operand1: Operand::Reference(arg1),
 | 
			
		||||
                  },
 | 
			
		||||
                  destination: Destination::Address(destination),
 | 
			
		||||
              }],
 | 
			
		||||
              binding: EpBinding::Single(destination),
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
        let not_enough_args = CompileError::NotEnoughArgs {
 | 
			
		||||
            fn_name: "add".into(),
 | 
			
		||||
            required: 2,
 | 
			
		||||
            actual: len,
 | 
			
		||||
        };
 | 
			
		||||
        const ERR: &str = "cannot use composite values (e.g. array) as arguments to Add";
 | 
			
		||||
        let EpBinding::Single(arg1) = args.pop().ok_or(not_enough_args.clone())? else {
 | 
			
		||||
            return Err(CompileError::InvalidOperand(ERR));
 | 
			
		||||
        };
 | 
			
		||||
        let EpBinding::Single(arg0) = args.pop().ok_or(not_enough_args)? else {
 | 
			
		||||
            return Err(CompileError::InvalidOperand(ERR));
 | 
			
		||||
        };
 | 
			
		||||
        let destination = ctx.next_address.offset_by(1);
 | 
			
		||||
        Ok(EvalPlan {
 | 
			
		||||
            instructions: vec![Instruction::BinaryArithmetic {
 | 
			
		||||
                arithmetic: BinaryArithmetic {
 | 
			
		||||
                    operation: kittycad_execution_plan::BinaryOperation::Add,
 | 
			
		||||
                    operand0: kittycad_execution_plan::Operand::Reference(arg0),
 | 
			
		||||
                    operand1: kittycad_execution_plan::Operand::Reference(arg1),
 | 
			
		||||
                },
 | 
			
		||||
                destination: Destination::Address(destination),
 | 
			
		||||
            }],
 | 
			
		||||
            binding: EpBinding::Single(destination),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    define_binary!($($r)*);
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
define_binary!(Add Log Max Min);
 | 
			
		||||
 | 
			
		||||
@ -67,6 +67,12 @@ pub fn sg_binding(
 | 
			
		||||
            actual: "function".to_owned(),
 | 
			
		||||
            arg_number,
 | 
			
		||||
        }),
 | 
			
		||||
        EpBinding::Constant(_) => Err(CompileError::ArgWrongType {
 | 
			
		||||
            fn_name,
 | 
			
		||||
            expected,
 | 
			
		||||
            actual: "constant".to_owned(),
 | 
			
		||||
            arg_number,
 | 
			
		||||
        }),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
pub fn single_binding(
 | 
			
		||||
@ -101,6 +107,12 @@ pub fn single_binding(
 | 
			
		||||
            actual: "function".to_owned(),
 | 
			
		||||
            arg_number,
 | 
			
		||||
        }),
 | 
			
		||||
        EpBinding::Constant(_) => Err(CompileError::ArgWrongType {
 | 
			
		||||
            fn_name,
 | 
			
		||||
            expected,
 | 
			
		||||
            actual: "constant".to_owned(),
 | 
			
		||||
            arg_number,
 | 
			
		||||
        }),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -136,6 +148,12 @@ pub fn sequence_binding(
 | 
			
		||||
            actual: "function".to_owned(),
 | 
			
		||||
            arg_number,
 | 
			
		||||
        }),
 | 
			
		||||
        EpBinding::Constant(_) => Err(CompileError::ArgWrongType {
 | 
			
		||||
            fn_name,
 | 
			
		||||
            expected,
 | 
			
		||||
            actual: "constant".to_owned(),
 | 
			
		||||
            arg_number,
 | 
			
		||||
        }),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
use std::{collections::HashMap, env};
 | 
			
		||||
 | 
			
		||||
use ep::{sketch_types, Destination, UnaryArithmetic};
 | 
			
		||||
use ept::{ListHeader, ObjectHeader};
 | 
			
		||||
use ep::{constants, sketch_types, Destination, UnaryArithmetic};
 | 
			
		||||
use ept::{ListHeader, ObjectHeader, Primitive};
 | 
			
		||||
use kittycad_modeling_cmds::shared::Point2d;
 | 
			
		||||
use kittycad_modeling_session::SessionBuilder;
 | 
			
		||||
use pretty_assertions::assert_eq;
 | 
			
		||||
@ -1414,3 +1414,31 @@ fn mod_and_pow() {
 | 
			
		||||
        ]
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
#[tokio::test]
 | 
			
		||||
async fn cos_sin_pi() {
 | 
			
		||||
    let program = "
 | 
			
		||||
        let x = cos(45.0)*10
 | 
			
		||||
        let y = sin(45.0)*10
 | 
			
		||||
        let z = PI
 | 
			
		||||
        ";
 | 
			
		||||
    let (_plan, scope, _) = must_plan(program);
 | 
			
		||||
    let Some(EpBinding::Single(x)) = scope.get("x") else {
 | 
			
		||||
        panic!("Unexpected binding for variable 'x': {:?}", scope.get("x"));
 | 
			
		||||
    };
 | 
			
		||||
    let Some(EpBinding::Single(y)) = scope.get("y") else {
 | 
			
		||||
        panic!("Unexpected binding for variable 'y': {:?}", scope.get("y"));
 | 
			
		||||
    };
 | 
			
		||||
    let Some(EpBinding::Constant(z)) = scope.get("z") else {
 | 
			
		||||
        panic!("Unexpected binding for variable 'z': {:?}", scope.get("z"));
 | 
			
		||||
    };
 | 
			
		||||
    let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
 | 
			
		||||
        .ast()
 | 
			
		||||
        .unwrap();
 | 
			
		||||
    let mem = crate::execute(ast, &mut None).await.unwrap();
 | 
			
		||||
    use ept::ReadMemory;
 | 
			
		||||
    assert_eq!(*mem.get(x).unwrap(), Primitive::from(5.253219888177298));
 | 
			
		||||
    assert_eq!(*mem.get(y).unwrap(), Primitive::from(8.509035245341185));
 | 
			
		||||
 | 
			
		||||
    // Constants don't live in memory.
 | 
			
		||||
    assert_eq!(*z, constants::PI);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user