1use crate::compiler::error::CompilerError;
2use crate::global::dxb_block::DXBBlock;
3use crate::global::protocol_structures::block_header::BlockHeader;
4use crate::global::protocol_structures::encrypted_header::EncryptedHeader;
5use crate::global::protocol_structures::routing_header;
6use crate::global::protocol_structures::routing_header::RoutingHeader;
7
8use crate::compiler::ast_parser::{DatexExpression, DatexScriptParser, TupleEntry, VariableType, parse, VariableMutType, VariableId};
9use crate::compiler::context::{CompilationContext, VirtualSlot};
10use crate::compiler::metadata::CompileMetadata;
11use crate::compiler::scope::CompilationScope;
12use crate::global::binary_codes::{InstructionCode, InternalSlot};
13use crate::values::core_values::decimal::decimal::Decimal;
14use crate::values::core_values::endpoint::Endpoint;
15use crate::values::value_container::ValueContainer;
16use std::cell::RefCell;
17use std::rc::Rc;
18use log::info;
19use datex_core::compiler::ast_parser::Slot;
20use crate::compiler::precompiler::{precompile_ast, AstMetadata, AstWithMetadata, VariableMetadata};
21
22pub mod ast_parser;
23pub mod context;
24pub mod error;
25mod lexer;
26pub mod metadata;
27pub mod scope;
28mod precompiler;
29
30#[derive(Clone, Default)]
31pub struct CompileOptions<'a> {
32 pub parser: Option<&'a DatexScriptParser<'a>>,
33 pub compile_scope: CompilationScope,
34}
35
36impl CompileOptions<'_> {
37 pub fn new_with_scope(compile_scope: CompilationScope) -> Self {
38 CompileOptions {
39 parser: None,
40 compile_scope,
41 }
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Eq)]
46pub enum StaticValueOrDXB {
47 StaticValue(Option<ValueContainer>),
48 Dxb(Vec<u8>),
49}
50
51impl From<Vec<u8>> for StaticValueOrDXB {
52 fn from(dxb: Vec<u8>) -> Self {
53 StaticValueOrDXB::Dxb(dxb)
54 }
55}
56
57
58#[derive(Debug, Clone, PartialEq, Eq, Copy)]
59pub enum VariableModel {
60 Constant,
63 VariableSlot,
66 VariableReference,
70}
71
72impl From<VariableRepresentation> for VariableModel {
73 fn from(value: VariableRepresentation) -> Self {
74 match value {
75 VariableRepresentation::Constant(_) => VariableModel::Constant,
76 VariableRepresentation::VariableSlot(_) => VariableModel::VariableSlot,
77 VariableRepresentation::VariableReference { .. } => VariableModel::VariableReference,
78 }
79 }
80}
81
82impl VariableModel {
83 pub fn infer(
85 variable_type: VariableType,
86 variable_metadata: Option<VariableMetadata>,
87 is_end_of_source_text: bool,
88 ) -> Self {
89 if variable_type == VariableType::Const {
91 VariableModel::Constant
92 }
93 else if variable_metadata.is_none() || variable_metadata.unwrap().is_cross_realm || !is_end_of_source_text {
98 VariableModel::VariableReference
99 }
100 else {
102 VariableModel::VariableSlot
103 }
104 }
105
106 pub fn infer_from_ast_metadata_and_type(
107 ast_metadata: &AstMetadata,
108 variable_id: Option<VariableId>,
109 variable_type: VariableType,
110 is_end_of_source_text: bool,
111 ) -> Self {
112 let variable_metadata = variable_id.and_then(|id| {
113 ast_metadata.variable_metadata(id)
114 });
115 Self::infer(variable_type, variable_metadata.cloned(), is_end_of_source_text)
116 }
117}
118
119
120#[derive(Debug, Clone, PartialEq, Eq, Copy)]
121pub enum VariableRepresentation {
122 Constant(VirtualSlot),
123 VariableSlot(VirtualSlot),
124 VariableReference {
125 variable_slot: VirtualSlot,
127 container_slot: VirtualSlot,
129 },
130}
131
132
133#[derive(Debug, Clone)]
135pub struct Variable {
136 pub name: String,
137 pub var_type: VariableType,
138 pub mut_type: VariableMutType,
139 pub representation: VariableRepresentation,
140}
141
142
143impl Variable {
144 pub fn new_const(
145 name: String,
146 var_type: VariableType,
147 mut_type: VariableMutType,
148 slot: VirtualSlot,
149 ) -> Self {
150 Variable {
151 name,
152 var_type,
153 mut_type,
154 representation: VariableRepresentation::Constant(slot),
155 }
156 }
157
158 pub fn new_variable_slot(
159 name: String,
160 var_type: VariableType,
161 mut_type: VariableMutType,
162 slot: VirtualSlot,
163 ) -> Self {
164 Variable {
165 name,
166 var_type,
167 mut_type,
168 representation: VariableRepresentation::VariableSlot(slot),
169 }
170 }
171
172 pub fn new_variable_reference(
173 name: String,
174 var_type: VariableType,
175 mut_type: VariableMutType,
176 variable_slot: VirtualSlot,
177 container_slot: VirtualSlot,
178 ) -> Self {
179 Variable {
180 name,
181 var_type,
182 mut_type,
183 representation: VariableRepresentation::VariableReference {
184 variable_slot,
185 container_slot,
186 },
187 }
188 }
189
190 pub fn slots(&self) -> Vec<VirtualSlot> {
191 match &self.representation {
192 VariableRepresentation::Constant(slot) => vec![*slot],
193 VariableRepresentation::VariableSlot(slot) => vec![*slot],
194 VariableRepresentation::VariableReference {
195 variable_slot,
196 container_slot,
197 } => {
198 vec![*variable_slot, *container_slot]
199 }
200 }
201 }
202}
203
204
205
206pub fn compile_block(datex_script: &str) -> Result<Vec<u8>, CompilerError> {
209 let (body, _) = compile_script(datex_script, CompileOptions::default())?;
210
211 let routing_header = RoutingHeader {
212 version: 2,
213 flags: routing_header::Flags::new(),
214 block_size_u16: Some(0),
215 block_size_u32: None,
216 sender: Endpoint::LOCAL,
217 receivers: routing_header::Receivers {
218 flags: routing_header::ReceiverFlags::new()
219 .with_has_endpoints(false)
220 .with_has_pointer_id(false)
221 .with_has_endpoint_keys(false),
222 pointer_id: None,
223 endpoints: None,
224 endpoints_with_keys: None,
225 },
226 ..RoutingHeader::default()
227 };
228
229 let block_header = BlockHeader::default();
230 let encrypted_header = EncryptedHeader::default();
231
232 let block =
233 DXBBlock::new(routing_header, block_header, encrypted_header, body);
234
235 let bytes = block
236 .to_bytes()
237 .map_err(CompilerError::SerializationError)?;
238 Ok(bytes)
239}
240
241pub fn compile_script<'a>(
243 datex_script: &'a str,
244 options: CompileOptions<'a>,
245) -> Result<(Vec<u8>, CompilationScope), CompilerError> {
246 compile_template(datex_script, &[], options)
247}
248
249pub fn extract_static_value_from_script(
253 datex_script: &str,
254) -> Result<Option<ValueContainer>, CompilerError> {
255 let res = parse(datex_script)?;
256 extract_static_value_from_ast(res).map(Some)
257}
258
259pub fn compile_template_with_refs<'a>(
262 datex_script: &'a str,
263 inserted_values: &[&ValueContainer],
264 options: CompileOptions<'a>,
265) -> Result<(Vec<u8>, CompilationScope), CompilerError> {
266 compile_template_or_return_static_value_with_refs(
267 datex_script,
268 inserted_values,
269 false,
270 options,
271 )
272 .map(|result| match result.0 {
273 StaticValueOrDXB::StaticValue(_) => unreachable!(),
274 StaticValueOrDXB::Dxb(dxb) => (dxb, result.1),
275 })
276}
277
278pub fn compile_script_or_return_static_value<'a>(
282 datex_script: &'a str,
283 options: CompileOptions<'a>,
284) -> Result<(StaticValueOrDXB, CompilationScope), CompilerError> {
285 compile_template_or_return_static_value_with_refs(
286 datex_script,
287 &[],
288 true,
289 options,
290 )
291}
292pub fn compile_template_or_return_static_value_with_refs<'a>(
294 datex_script: &'a str,
295 inserted_values: &[&ValueContainer],
296 return_static_value: bool,
297 options: CompileOptions<'a>,
298) -> Result<(StaticValueOrDXB, CompilationScope), CompilerError> {
299 if datex_script == "?" {
301 if inserted_values.len() != 1 {
302 return Err(CompilerError::InvalidPlaceholderCount);
303 }
304 let result =
305 compile_value(inserted_values[0]).map(StaticValueOrDXB::from)?;
306 return Ok((result, options.compile_scope));
307 }
308
309 let ast = parse(datex_script)?;
310
311 let buffer = RefCell::new(Vec::with_capacity(256));
312 let compilation_context = CompilationContext::new(buffer, inserted_values, options.compile_scope.once);
313
314 if return_static_value {
315 let scope = compile_ast(
316 &compilation_context,
317 ast.clone(),
318 options.compile_scope,
319 )?;
320
321 if !*compilation_context.has_non_static_value.borrow() {
322 if let Ok(value) = ValueContainer::try_from(ast) {
323 return Ok((
324 StaticValueOrDXB::StaticValue(Some(value.clone())),
325 scope,
326 ));
327 }
328 Ok((StaticValueOrDXB::StaticValue(None), scope))
329 } else {
330 Ok((
332 StaticValueOrDXB::Dxb(compilation_context.buffer.take()),
333 scope,
334 ))
335 }
336 } else {
337 let scope =
338 compile_ast(&compilation_context, ast, options.compile_scope)?;
339 Ok((
341 StaticValueOrDXB::Dxb(compilation_context.buffer.take()),
342 scope,
343 ))
344 }
345}
346
347pub fn compile_template<'a>(
349 datex_script: &'a str,
350 inserted_values: &[ValueContainer],
351 options: CompileOptions<'a>,
352) -> Result<(Vec<u8>, CompilationScope), CompilerError> {
353 compile_template_with_refs(
354 datex_script,
355 &inserted_values.iter().collect::<Vec<_>>(),
356 options,
357 )
358}
359
360pub fn compile_value(value: &ValueContainer) -> Result<Vec<u8>, CompilerError> {
361 let buffer = RefCell::new(Vec::with_capacity(256));
362 let compilation_scope = CompilationContext::new(buffer, &[], true);
363
364 compilation_scope.insert_value_container(value);
365
366 Ok(compilation_scope.buffer.take())
367}
368
369fn extract_static_value_from_ast(
373 ast: DatexExpression,
374) -> Result<ValueContainer, CompilerError> {
375 if let DatexExpression::Placeholder = ast {
376 return Err(CompilerError::NonStaticValue);
377 }
378 ValueContainer::try_from(ast).map_err(|_| CompilerError::NonStaticValue)
379}
380
381#[macro_export]
389macro_rules! compile {
390 ($fmt:literal $(, $arg:expr )* $(,)?) => {
391 {
392 let script: &str = $fmt.into();
393 let values: &[$crate::values::value_container::ValueContainer] = &[$($arg.into()),*];
394
395 $crate::compiler::compile_template(&script, values, $crate::compiler::CompileOptions::default())
396 }
397 }
398}
399
400pub fn compile_ast(
401 compilation_context: &CompilationContext,
402 ast: DatexExpression,
403 mut scope: CompilationScope,
404) -> Result<CompilationScope, CompilerError> {
405 if scope.once {
407 if scope.was_used {
408 return Err(CompilerError::OnceScopeUsedMultipleTimes);
409 }
410 scope.was_used = true;
412 }
413 let ast_with_metadata = if let Some(precompiler_data) = &scope.precompiler_data {
414 precompile_ast(
416 ast,
417 precompiler_data.ast_metadata.clone(),
418 &mut precompiler_data.precompiler_scope_stack.borrow_mut(),
419 )?
420 }
421 else {
422 AstWithMetadata::new_without_metadata(ast)
424 };
425
426 compile_ast_with_metadata(
427 compilation_context,
428 ast_with_metadata,
429 scope,
430 )
431}
432
433pub fn compile_ast_with_metadata(
434 compilation_context: &CompilationContext,
435 ast_with_metadata: AstWithMetadata,
436 scope: CompilationScope,
437) -> Result<CompilationScope, CompilerError> {
438 let scope = compile_expression(
439 compilation_context,
440 ast_with_metadata,
441 CompileMetadata::outer(),
442 scope,
443 )?;
444
445 compilation_context.remap_virtual_slots();
447 Ok(scope)
448}
449
450fn compile_expression(
451 compilation_context: &CompilationContext,
452 ast_with_metadata: AstWithMetadata,
453 meta: CompileMetadata,
454 mut scope: CompilationScope,
455) -> Result<CompilationScope, CompilerError> {
456 let metadata = ast_with_metadata.metadata;
457 match ast_with_metadata.ast {
458 DatexExpression::Integer(int) => {
459 compilation_context.insert_int(int.0.as_i64().unwrap());
460 }
461 DatexExpression::Decimal(decimal) => match &decimal {
462 Decimal::Finite(big_decimal) if big_decimal.is_integer() => {
463 if let Some(int) = big_decimal.to_i16() {
464 compilation_context.insert_float_as_i16(int);
465 } else if let Some(int) = big_decimal.to_i32() {
466 compilation_context.insert_float_as_i32(int);
467 } else {
468 compilation_context.insert_decimal(&decimal);
469 }
470 }
471 _ => {
472 compilation_context.insert_decimal(&decimal);
473 }
474 },
475 DatexExpression::Text(text) => {
476 compilation_context.insert_text(&text);
477 }
478 DatexExpression::Boolean(boolean) => {
479 compilation_context.insert_boolean(boolean);
480 }
481 DatexExpression::Endpoint(endpoint) => {
482 compilation_context.insert_endpoint(&endpoint);
483 }
484 DatexExpression::Null => {
485 compilation_context.append_binary_code(InstructionCode::NULL);
486 }
487 DatexExpression::Array(array) => {
488 compilation_context
489 .append_binary_code(InstructionCode::ARRAY_START);
490 for item in array {
491 scope = compile_expression(
492 compilation_context,
493 AstWithMetadata::new(item, &metadata),
494 CompileMetadata::default(),
495 scope,
496 )?;
497 }
498 compilation_context.append_binary_code(InstructionCode::SCOPE_END);
499 }
500 DatexExpression::Tuple(tuple) => {
501 compilation_context
502 .append_binary_code(InstructionCode::TUPLE_START);
503 for entry in tuple {
504 match entry {
505 TupleEntry::KeyValue(key, value) => {
506 scope = compile_key_value_entry(
507 compilation_context,
508 key,
509 value,
510 &metadata,
511 scope,
512 )?;
513 }
514 TupleEntry::Value(value) => {
515 scope = compile_expression(
516 compilation_context,
517 AstWithMetadata::new(value, &metadata),
518 CompileMetadata::default(),
519 scope,
520 )?;
521 }
522 }
523 }
524 compilation_context.append_binary_code(InstructionCode::SCOPE_END);
525 }
526 DatexExpression::Object(object) => {
527 compilation_context
528 .append_binary_code(InstructionCode::OBJECT_START);
529 for (key, value) in object {
530 scope = compile_key_value_entry(
532 compilation_context,
533 key,
534 value,
535 &metadata,
536 scope,
537 )?;
538 }
539 compilation_context.append_binary_code(InstructionCode::SCOPE_END);
540 }
541
542 DatexExpression::Placeholder => {
543 compilation_context.insert_value_container(
544 compilation_context
545 .inserted_values
546 .borrow()
547 .get(compilation_context.inserted_value_index.get())
548 .unwrap(),
549 );
550 compilation_context.inserted_value_index.update(|x| x + 1);
551 }
552
553 DatexExpression::Statements(mut statements) => {
555 compilation_context.mark_has_non_static_value();
556 if statements.len() == 1 && !statements[0].is_terminated {
558 scope = compile_expression(
559 compilation_context,
560 AstWithMetadata::new(
561 statements.remove(0).expression,
562 &metadata
563 ),
564 CompileMetadata::default(),
565 scope,
566 )?;
567 } else {
568 let mut child_scope = if !meta.is_outer_context() {
570 compilation_context
571 .append_binary_code(InstructionCode::SCOPE_START);
572 scope.push()
573 } else {
574 scope
575 };
576 for statement in statements {
577 child_scope = compile_expression(
578 compilation_context,
579 AstWithMetadata::new(statement.expression, &metadata),
580 CompileMetadata::default(),
581 child_scope,
582 )?;
583 if statement.is_terminated {
585 compilation_context.append_binary_code(
586 InstructionCode::CLOSE_AND_STORE,
587 );
588 }
589 }
590 if !meta.is_outer_context() {
591 let scope_data = child_scope
592 .pop()
593 .ok_or(CompilerError::ScopePopError)?;
594 scope = scope_data.0; for slot_address in scope_data.1 {
597 compilation_context
598 .append_binary_code(InstructionCode::DROP_SLOT);
599 compilation_context
601 .insert_virtual_slot_address(slot_address);
602 }
603 compilation_context
604 .append_binary_code(InstructionCode::SCOPE_END);
605 } else {
606 scope = child_scope;
607 }
608 }
609 }
610
611 DatexExpression::BinaryOperation(operator, a, b) => {
613 compilation_context.mark_has_non_static_value();
614 compilation_context
616 .append_binary_code(InstructionCode::from(&operator));
617 scope = compile_expression(
618 compilation_context,
619 AstWithMetadata::new(*a, &metadata),
620 CompileMetadata::default(),
621 scope,
622 )?;
623 scope = compile_expression(
624 compilation_context,
625 AstWithMetadata::new(*b, &metadata),
626 CompileMetadata::default(),
627 scope,
628 )?;
629 }
630
631 DatexExpression::ApplyChain(val, operands) => {
633 compilation_context.mark_has_non_static_value();
634 }
636
637 DatexExpression::VariableDeclaration(id, var_type, mut_type, name, expression) => {
640 compilation_context.mark_has_non_static_value();
641
642 let virtual_slot_addr = scope.get_next_virtual_slot();
644 compilation_context
645 .append_binary_code(InstructionCode::ALLOCATE_SLOT);
646 compilation_context.insert_virtual_slot_address(
647 VirtualSlot::local(virtual_slot_addr),
648 );
649 if mut_type == VariableMutType::Mutable {
651 compilation_context
652 .append_binary_code(InstructionCode::CREATE_REF);
653 }
654 scope = compile_expression(
656 compilation_context,
657 AstWithMetadata::new(*expression, &metadata),
658 CompileMetadata::default(),
659 scope,
660 )?;
661
662 let variable_model = VariableModel::infer_from_ast_metadata_and_type(
663 &metadata.borrow(),
664 id,
665 var_type,
666 compilation_context.is_end_of_source_text,
667 );
668 info!("variable model for {name}: {variable_model:?}");
669
670 let variable = match variable_model {
672 VariableModel::VariableReference => {
673 compilation_context
675 .append_binary_code(InstructionCode::SCOPE_END);
676 let virtual_slot_addr_for_var = scope.get_next_virtual_slot();
678 compilation_context
679 .append_binary_code(InstructionCode::ALLOCATE_SLOT);
680 compilation_context.insert_virtual_slot_address(
681 VirtualSlot::local(virtual_slot_addr_for_var),
682 );
683 compilation_context
685 .append_binary_code(InstructionCode::CREATE_REF);
686 compilation_context
688 .append_binary_code(InstructionCode::GET_SLOT);
689 compilation_context.insert_virtual_slot_address(
690 VirtualSlot::local(virtual_slot_addr),
691 );
692
693 Variable::new_variable_reference(
694 name.clone(),
695 var_type,
696 mut_type,
697 VirtualSlot::local(virtual_slot_addr_for_var),
698 VirtualSlot::local(virtual_slot_addr),
699 )
700 }
701 VariableModel::Constant => {
702 Variable::new_const(
703 name.clone(),
704 var_type,
705 mut_type,
706 VirtualSlot::local(virtual_slot_addr),
707 )
708 }
709 VariableModel::VariableSlot => {
710 Variable::new_variable_slot(
711 name.clone(),
712 var_type,
713 mut_type,
714 VirtualSlot::local(virtual_slot_addr),
715 )
716 }
717 };
718
719 scope.register_variable_slot(variable);
720
721 compilation_context.append_binary_code(InstructionCode::SCOPE_END);
722 }
723
724 DatexExpression::VariableAssignment(id, name, expression) => {
726 compilation_context.mark_has_non_static_value();
727 let (virtual_slot, var_type, mut_type) = scope
729 .resolve_variable_name_to_virtual_slot(&name)
730 .ok_or_else(|| {
731 CompilerError::UndeclaredVariable(name.clone())
732 })?;
733
734 if var_type == VariableType::Const {
736 return Err(CompilerError::AssignmentToConst(name.clone()));
737 }
738
739 info!("append variable virtual slot: {virtual_slot:?}, name: {name}");
741 compilation_context
742 .append_binary_code(InstructionCode::SET_SLOT);
743 compilation_context.insert_virtual_slot_address(virtual_slot);
744 scope = compile_expression(
746 compilation_context,
747 AstWithMetadata::new(*expression, &metadata),
748 CompileMetadata::default(),
749 scope,
750 )?;
751 compilation_context.append_binary_code(InstructionCode::SCOPE_END);
753 }
754
755 DatexExpression::Variable(id, name) => {
757 compilation_context.mark_has_non_static_value();
758 let (virtual_slot, ..) = scope
760 .resolve_variable_name_to_virtual_slot(&name)
761 .ok_or_else(|| {
762 CompilerError::UndeclaredVariable(name.clone())
763 })?;
764 compilation_context.append_binary_code(InstructionCode::GET_SLOT);
766 compilation_context.insert_virtual_slot_address(virtual_slot);
767 }
768
769 DatexExpression::RemoteExecution(caller, script) => {
771 compilation_context.mark_has_non_static_value();
772
773 compilation_context
775 .append_binary_code(InstructionCode::REMOTE_EXECUTION);
776 scope = compile_expression(
778 compilation_context,
779 AstWithMetadata::new(*caller, &metadata),
780 CompileMetadata::default(),
781 scope,
782 )?;
783
784 let execution_block_ctx =
786 CompilationContext::new(RefCell::new(Vec::with_capacity(256)), &[], true);
787 let external_scope = compile_ast_with_metadata(
788 &execution_block_ctx,
789 AstWithMetadata::new(
790 *script,
791 &metadata,
792 ),
793 CompilationScope::new_with_external_parent_scope(scope),
794 )?;
795 scope = external_scope.pop_external().ok_or_else(|| {
797 CompilerError::ScopePopError
798 })?;
799
800 let external_slots = execution_block_ctx.external_slots();
801 compilation_context
803 .append_binary_code(InstructionCode::EXECUTION_BLOCK);
804 compilation_context
806 .append_u32(execution_block_ctx.buffer.borrow().len() as u32);
807 compilation_context.append_u32(external_slots.len() as u32);
809 for slot in external_slots {
810 compilation_context.insert_virtual_slot_address(slot.upgrade());
811 }
812
813 compilation_context.append_buffer(
815 &execution_block_ctx.buffer.borrow(),
816 )
817 }
818
819 DatexExpression::Slot(Slot::Named(name)) => {
821 match name.as_str() {
822 "endpoint" => {
823 compilation_context.append_binary_code(
824 InstructionCode::GET_SLOT,
825 );
826 compilation_context.append_u32(InternalSlot::ENDPOINT as u32);
827 }
828 _ => {
829 return Err(CompilerError::InvalidSlotName(name.clone()));
831 }
832 }
833 }
834
835 _ => return Err(CompilerError::UnexpectedTerm(ast_with_metadata.ast)),
836 }
837
838 Ok(scope)
839}
840
841fn compile_key_value_entry(
842 compilation_scope: &CompilationContext,
843 key: DatexExpression,
844 value: DatexExpression,
845 metadata: &Rc<RefCell<AstMetadata>>,
846 mut scope: CompilationScope,
847) -> Result<CompilationScope, CompilerError> {
848 match key {
849 DatexExpression::Text(text) => {
851 compilation_scope.insert_key_string(&text);
852 }
853 _ => {
855 compilation_scope
856 .append_binary_code(InstructionCode::KEY_VALUE_DYNAMIC);
857 scope = compile_expression(
858 compilation_scope,
859 AstWithMetadata::new(key, metadata),
860 CompileMetadata::default(),
861 scope,
862 )?;
863 }
864 };
865 scope = compile_expression(
867 compilation_scope,
868 AstWithMetadata::new(value, metadata),
869 CompileMetadata::default(),
870 scope,
871 )?;
872 Ok(scope)
873}
874
875#[cfg(test)]
876pub mod tests {
877 use std::assert_matches::assert_matches;
878 use super::{
879 CompileOptions, CompilationContext, CompilationScope, StaticValueOrDXB, compile_ast,
880 compile_script, compile_script_or_return_static_value,
881 compile_template,
882 };
883 use std::cell::RefCell;
884 use std::io::Read;
885 use std::vec;
886
887 use crate::{global::binary_codes::InstructionCode, logger::init_logger_debug};
888 use log::*;
889 use datex_core::compiler::error::CompilerError;
890 use crate::compiler::ast_parser::parse;
891 use crate::values::core_values::integer::integer::Integer;
892
893 fn compile_and_log(datex_script: &str) -> Vec<u8> {
894 init_logger_debug();
895 let (result, _) =
896 compile_script(datex_script, CompileOptions::default()).unwrap();
897 info!(
898 "{:?}",
899 result
900 .iter()
901 .map(|x| InstructionCode::try_from(*x).map(|x| x.to_string()))
902 .map(|x| x.unwrap_or_else(|_| "Unknown".to_string()))
903 .collect::<Vec<_>>()
904 );
905 result
906 }
907
908 fn get_compilation_scope(script: &str) -> CompilationContext {
909 let ast = parse(script);
910 let ast = ast.unwrap();
911 let buffer = RefCell::new(Vec::with_capacity(256));
912 let compilation_scope = CompilationContext::new(buffer, &[], true);
913 compile_ast(&compilation_scope, ast, CompilationScope::default()).unwrap();
914 compilation_scope
915 }
916
917 #[test]
918 fn test_simple_multiplication() {
919 init_logger_debug();
920
921 let lhs: u8 = 1;
922 let rhs: u8 = 2;
923 let datex_script = format!("{lhs} * {rhs}"); let result = compile_and_log(&datex_script);
925 assert_eq!(
926 result,
927 vec![
928 InstructionCode::MULTIPLY.into(),
929 InstructionCode::INT_8.into(),
930 lhs,
931 InstructionCode::INT_8.into(),
932 rhs,
933 ]
934 );
935 }
936
937 #[test]
938 fn test_simple_multiplication_close() {
939 init_logger_debug();
940
941 let lhs: u8 = 1;
942 let rhs: u8 = 2;
943 let datex_script = format!("{lhs} * {rhs};"); let result = compile_and_log(&datex_script);
945 assert_eq!(
946 result,
947 vec![
948 InstructionCode::MULTIPLY.into(),
949 InstructionCode::INT_8.into(),
950 lhs,
951 InstructionCode::INT_8.into(),
952 rhs,
953 InstructionCode::CLOSE_AND_STORE.into()
954 ]
955 );
956 }
957
958 #[test]
959 fn test_is_operator() {
960 init_logger_debug();
961
962 let datex_script = "1 is 2".to_string();
964 let result = compile_and_log(&datex_script);
965 assert_eq!(
966 result,
967 vec![
968 InstructionCode::IS.into(),
969 InstructionCode::INT_8.into(),
970 1,
971 InstructionCode::INT_8.into(),
972 2
973 ]
974 );
975
976 let datex_script = "const mut a = 42; const mut b = 69; a is b".to_string(); let result = compile_and_log(&datex_script);
978 assert_eq!(
979 result,
980 vec![
981 InstructionCode::ALLOCATE_SLOT.into(),
983 0,
984 0,
985 0,
986 0,
987 InstructionCode::CREATE_REF.into(),
988 InstructionCode::INT_8.into(),
989 42,
990 InstructionCode::SCOPE_END.into(),
991 InstructionCode::CLOSE_AND_STORE.into(),
992 InstructionCode::ALLOCATE_SLOT.into(),
994 1,
995 0,
996 0,
997 0,
998 InstructionCode::CREATE_REF.into(),
999 InstructionCode::INT_8.into(),
1000 69,
1001 InstructionCode::SCOPE_END.into(),
1002 InstructionCode::CLOSE_AND_STORE.into(),
1003 InstructionCode::IS.into(),
1005 InstructionCode::GET_SLOT.into(),
1006 0,
1007 0,
1008 0,
1009 0, InstructionCode::GET_SLOT.into(),
1011 1,
1012 0,
1013 0,
1014 0, ]
1016 );
1017 }
1018
1019 #[test]
1020 fn test_equality_operator() {
1021 init_logger_debug();
1022
1023 let lhs: u8 = 1;
1024 let rhs: u8 = 2;
1025 let datex_script = format!("{lhs} == {rhs}"); let result = compile_and_log(&datex_script);
1027 assert_eq!(
1028 result,
1029 vec![
1030 InstructionCode::STRUCTURAL_EQUAL.into(),
1031 InstructionCode::INT_8.into(),
1032 lhs,
1033 InstructionCode::INT_8.into(),
1034 rhs,
1035 ]
1036 );
1037
1038 let datex_script = format!("{lhs} === {rhs}"); let result = compile_and_log(&datex_script);
1040 assert_eq!(
1041 result,
1042 vec![
1043 InstructionCode::EQUAL.into(),
1044 InstructionCode::INT_8.into(),
1045 lhs,
1046 InstructionCode::INT_8.into(),
1047 rhs,
1048 ]
1049 );
1050
1051 let datex_script = format!("{lhs} != {rhs}"); let result = compile_and_log(&datex_script);
1053 assert_eq!(
1054 result,
1055 vec![
1056 InstructionCode::NOT_STRUCTURAL_EQUAL.into(),
1057 InstructionCode::INT_8.into(),
1058 lhs,
1059 InstructionCode::INT_8.into(),
1060 rhs,
1061 ]
1062 );
1063 let datex_script = format!("{lhs} !== {rhs}"); let result = compile_and_log(&datex_script);
1065 assert_eq!(
1066 result,
1067 vec![
1068 InstructionCode::NOT_EQUAL.into(),
1069 InstructionCode::INT_8.into(),
1070 lhs,
1071 InstructionCode::INT_8.into(),
1072 rhs,
1073 ]
1074 );
1075 }
1076
1077 #[test]
1078 fn test_simple_addition() {
1079 init_logger_debug();
1080
1081 let lhs: u8 = 1;
1082 let rhs: u8 = 2;
1083 let datex_script = format!("{lhs} + {rhs}"); let result = compile_and_log(&datex_script);
1085 assert_eq!(
1086 result,
1087 vec![
1088 InstructionCode::ADD.into(),
1089 InstructionCode::INT_8.into(),
1090 lhs,
1091 InstructionCode::INT_8.into(),
1092 rhs
1093 ]
1094 );
1095
1096 let datex_script = format!("{lhs} + {rhs};"); let result = compile_and_log(&datex_script);
1098 assert_eq!(
1099 result,
1100 vec![
1101 InstructionCode::ADD.into(),
1102 InstructionCode::INT_8.into(),
1103 lhs,
1104 InstructionCode::INT_8.into(),
1105 rhs,
1106 InstructionCode::CLOSE_AND_STORE.into()
1107 ]
1108 );
1109 }
1110
1111 #[test]
1112 fn test_multi_addition() {
1113 init_logger_debug();
1114
1115 let op1: u8 = 1;
1116 let op2: u8 = 2;
1117 let op3: u8 = 3;
1118 let op4: u8 = 4;
1119
1120 let datex_script = format!("{op1} + {op2} + {op3} + {op4}"); let result = compile_and_log(&datex_script);
1122 assert_eq!(
1123 result,
1124 vec![
1125 InstructionCode::ADD.into(),
1126 InstructionCode::ADD.into(),
1127 InstructionCode::ADD.into(),
1128 InstructionCode::INT_8.into(),
1129 op1,
1130 InstructionCode::INT_8.into(),
1131 op2,
1132 InstructionCode::INT_8.into(),
1133 op3,
1134 InstructionCode::INT_8.into(),
1135 op4,
1136 ]
1137 );
1138 }
1139
1140 #[test]
1141 fn test_mixed_calculation() {
1142 init_logger_debug();
1143
1144 let op1: u8 = 1;
1145 let op2: u8 = 2;
1146 let op3: u8 = 3;
1147 let op4: u8 = 4;
1148
1149 let datex_script = format!("{op1} * {op2} + {op3} * {op4}"); let result = compile_and_log(&datex_script);
1151 assert_eq!(
1152 result,
1153 vec![
1154 InstructionCode::ADD.into(),
1155 InstructionCode::MULTIPLY.into(),
1156 InstructionCode::INT_8.into(),
1157 op1,
1158 InstructionCode::INT_8.into(),
1159 op2,
1160 InstructionCode::MULTIPLY.into(),
1161 InstructionCode::INT_8.into(),
1162 op3,
1163 InstructionCode::INT_8.into(),
1164 op4,
1165 ]
1166 );
1167 }
1168
1169 #[test]
1170 fn test_complex_addition() {
1171 init_logger_debug();
1172
1173 let a: u8 = 1;
1174 let b: u8 = 2;
1175 let c: u8 = 3;
1176 let datex_script = format!("{a} + ({b} + {c})"); let result = compile_and_log(&datex_script);
1178
1179 assert_eq!(
1183 result,
1184 vec![
1185 InstructionCode::ADD.into(),
1186 InstructionCode::INT_8.into(),
1187 a,
1188 InstructionCode::ADD.into(),
1189 InstructionCode::INT_8.into(),
1190 b,
1191 InstructionCode::INT_8.into(),
1192 c,
1193 ]
1194 );
1195 }
1196
1197 #[test]
1198 fn test_complex_addition_and_subtraction() {
1199 init_logger_debug();
1200
1201 let a: u8 = 1;
1202 let b: u8 = 2;
1203 let c: u8 = 3;
1204 let datex_script = format!("{a} + ({b} - {c})"); let result = compile_and_log(&datex_script);
1206 assert_eq!(
1207 result,
1208 vec![
1209 InstructionCode::ADD.into(),
1210 InstructionCode::INT_8.into(),
1211 a,
1212 InstructionCode::SUBTRACT.into(),
1213 InstructionCode::INT_8.into(),
1214 b,
1215 InstructionCode::INT_8.into(),
1216 c,
1217 ]
1218 );
1219 }
1220
1221 #[test]
1223 fn test_integer_u8() {
1224 init_logger_debug();
1225 let val: u8 = 42;
1226 let datex_script = format!("{val}"); let result = compile_and_log(&datex_script);
1228 assert_eq!(result, vec![InstructionCode::INT_8.into(), val,]);
1229 }
1230
1231 #[test]
1233 fn test_decimal() {
1234 init_logger_debug();
1235 let datex_script = "42.0";
1236 let result = compile_and_log(datex_script);
1237 let bytes = 42_i16.to_le_bytes();
1238
1239 let mut expected: Vec<u8> =
1240 vec![InstructionCode::DECIMAL_AS_INT_16.into()];
1241 expected.extend(bytes);
1242
1243 assert_eq!(result, expected);
1244 }
1245
1246 #[test]
1248 fn test_short_text() {
1249 init_logger_debug();
1250 let val = "unyt";
1251 let datex_script = format!("\"{val}\""); let result = compile_and_log(&datex_script);
1253 let mut expected: Vec<u8> =
1254 vec![InstructionCode::SHORT_TEXT.into(), val.len() as u8];
1255 expected.extend(val.bytes());
1256 assert_eq!(result, expected);
1257 }
1258
1259 #[test]
1261 fn test_empty_array() {
1262 init_logger_debug();
1263 let datex_script = "[]";
1264 let result = compile_and_log(datex_script);
1265 let expected: Vec<u8> = vec![
1266 InstructionCode::ARRAY_START.into(),
1267 InstructionCode::SCOPE_END.into(),
1268 ];
1269 assert_eq!(result, expected);
1270 }
1271
1272 #[test]
1274 fn test_single_element_array() {
1275 init_logger_debug();
1276 let datex_script = "[42]";
1277 let result = compile_and_log(datex_script);
1278 assert_eq!(
1279 result,
1280 vec![
1281 InstructionCode::ARRAY_START.into(),
1282 InstructionCode::INT_8.into(),
1283 42,
1284 InstructionCode::SCOPE_END.into(),
1285 ]
1286 );
1287 }
1288
1289 #[test]
1291 fn test_multi_element_array() {
1292 init_logger_debug();
1293 let datex_script = "[1, 2, 3]";
1294 let result = compile_and_log(datex_script);
1295 assert_eq!(
1296 result,
1297 vec![
1298 InstructionCode::ARRAY_START.into(),
1299 InstructionCode::INT_8.into(),
1300 1,
1301 InstructionCode::INT_8.into(),
1302 2,
1303 InstructionCode::INT_8.into(),
1304 3,
1305 InstructionCode::SCOPE_END.into(),
1306 ]
1307 );
1308 }
1309
1310 #[test]
1312 fn test_nested_arrays() {
1313 init_logger_debug();
1314 let datex_script = "[1, [2, 3], 4]";
1315 let result = compile_and_log(datex_script);
1316 assert_eq!(
1317 result,
1318 vec![
1319 InstructionCode::ARRAY_START.into(),
1320 InstructionCode::INT_8.into(),
1321 1,
1322 InstructionCode::ARRAY_START.into(),
1323 InstructionCode::INT_8.into(),
1324 2,
1325 InstructionCode::INT_8.into(),
1326 3,
1327 InstructionCode::SCOPE_END.into(),
1328 InstructionCode::INT_8.into(),
1329 4,
1330 InstructionCode::SCOPE_END.into(),
1331 ]
1332 );
1333 }
1334
1335 #[test]
1337 fn test_array_with_expressions() {
1338 init_logger_debug();
1339 let datex_script = "[1 + 2, 3 * 4]";
1340 let result = compile_and_log(datex_script);
1341 assert_eq!(
1342 result,
1343 vec![
1344 InstructionCode::ARRAY_START.into(),
1345 InstructionCode::ADD.into(),
1346 InstructionCode::INT_8.into(),
1347 1,
1348 InstructionCode::INT_8.into(),
1349 2,
1350 InstructionCode::MULTIPLY.into(),
1351 InstructionCode::INT_8.into(),
1352 3,
1353 InstructionCode::INT_8.into(),
1354 4,
1355 InstructionCode::SCOPE_END.into(),
1356 ]
1357 );
1358 }
1359
1360 #[test]
1362 fn test_array_with_mixed_expressions() {
1363 init_logger_debug();
1364 let datex_script = "[1, 2, 3 + 4]";
1365 let result = compile_and_log(datex_script);
1366 assert_eq!(
1367 result,
1368 vec![
1369 InstructionCode::ARRAY_START.into(),
1370 InstructionCode::INT_8.into(),
1371 1,
1372 InstructionCode::INT_8.into(),
1373 2,
1374 InstructionCode::ADD.into(),
1375 InstructionCode::INT_8.into(),
1376 3,
1377 InstructionCode::INT_8.into(),
1378 4,
1379 InstructionCode::SCOPE_END.into(),
1380 ]
1381 );
1382 }
1383
1384 #[test]
1386 fn test_tuple() {
1387 init_logger_debug();
1388 let datex_script = "(1, 2, 3)";
1389 let result = compile_and_log(datex_script);
1390 assert_eq!(
1391 result,
1392 vec![
1393 InstructionCode::TUPLE_START.into(),
1394 InstructionCode::INT_8.into(),
1395 1,
1396 InstructionCode::INT_8.into(),
1397 2,
1398 InstructionCode::INT_8.into(),
1399 3,
1400 InstructionCode::SCOPE_END.into(),
1401 ]
1402 );
1403 }
1404
1405 #[test]
1407 fn test_nested_tuple() {
1408 init_logger_debug();
1409 let datex_script = "(1, (2, 3), 4)";
1410 let result = compile_and_log(datex_script);
1411 assert_eq!(
1412 result,
1413 vec![
1414 InstructionCode::TUPLE_START.into(),
1415 InstructionCode::INT_8.into(),
1416 1,
1417 InstructionCode::TUPLE_START.into(),
1418 InstructionCode::INT_8.into(),
1419 2,
1420 InstructionCode::INT_8.into(),
1421 3,
1422 InstructionCode::SCOPE_END.into(),
1423 InstructionCode::INT_8.into(),
1424 4,
1425 InstructionCode::SCOPE_END.into(),
1426 ]
1427 );
1428 }
1429
1430 #[test]
1432 fn test_tuple_without_parentheses() {
1433 init_logger_debug();
1434 let datex_script = "1, 2, 3";
1435 let result = compile_and_log(datex_script);
1436 assert_eq!(
1437 result,
1438 vec![
1439 InstructionCode::TUPLE_START.into(),
1440 InstructionCode::INT_8.into(),
1441 1,
1442 InstructionCode::INT_8.into(),
1443 2,
1444 InstructionCode::INT_8.into(),
1445 3,
1446 InstructionCode::SCOPE_END.into(),
1447 ]
1448 );
1449 }
1450
1451 #[test]
1453 fn test_key_value_tuple() {
1454 init_logger_debug();
1455 let datex_script = "key: 42";
1456 let result = compile_and_log(datex_script);
1457 let expected = vec![
1458 InstructionCode::TUPLE_START.into(),
1459 InstructionCode::KEY_VALUE_SHORT_TEXT.into(),
1460 3, b'k',
1462 b'e',
1463 b'y',
1464 InstructionCode::INT_8.into(),
1465 42,
1466 InstructionCode::SCOPE_END.into(),
1467 ];
1468 assert_eq!(result, expected);
1469 }
1470
1471 #[test]
1473 fn test_key_value_string() {
1474 init_logger_debug();
1475 let datex_script = "\"key\": 42";
1476 let result = compile_and_log(datex_script);
1477 let expected = vec![
1478 InstructionCode::TUPLE_START.into(),
1479 InstructionCode::KEY_VALUE_SHORT_TEXT.into(),
1480 3, b'k',
1482 b'e',
1483 b'y',
1484 InstructionCode::INT_8.into(),
1485 42,
1486 InstructionCode::SCOPE_END.into(),
1487 ];
1488 assert_eq!(result, expected);
1489 }
1490
1491 #[test]
1493 fn test_key_value_integer() {
1494 init_logger_debug();
1495 let datex_script = "10: 42";
1496 let result = compile_and_log(datex_script);
1497 let expected = vec![
1498 InstructionCode::TUPLE_START.into(),
1499 InstructionCode::KEY_VALUE_DYNAMIC.into(),
1500 InstructionCode::INT_8.into(),
1501 10,
1502 InstructionCode::INT_8.into(),
1503 42,
1504 InstructionCode::SCOPE_END.into(),
1505 ];
1506 assert_eq!(result, expected);
1507 }
1508
1509 #[test]
1511 fn test_key_value_long_text() {
1512 init_logger_debug();
1513 let long_key = "a".repeat(300);
1514 let datex_script = format!("\"{long_key}\": 42");
1515 let result = compile_and_log(&datex_script);
1516 let mut expected: Vec<u8> = vec![
1517 InstructionCode::TUPLE_START.into(),
1518 InstructionCode::KEY_VALUE_DYNAMIC.into(),
1519 InstructionCode::TEXT.into(),
1520 ];
1521 expected.extend((long_key.len() as u32).to_le_bytes());
1522 expected.extend(long_key.as_bytes());
1523 expected.extend(vec![
1524 InstructionCode::INT_8.into(),
1525 42,
1526 InstructionCode::SCOPE_END.into(),
1527 ]);
1528 assert_eq!(result, expected);
1529 }
1530
1531 #[test]
1533 fn test_dynamic_key_value() {
1534 init_logger_debug();
1535 let datex_script = "(1 + 2): 42";
1536 let result = compile_and_log(datex_script);
1537 let expected = [
1538 InstructionCode::TUPLE_START.into(),
1539 InstructionCode::KEY_VALUE_DYNAMIC.into(),
1540 InstructionCode::ADD.into(),
1541 InstructionCode::INT_8.into(),
1542 1,
1543 InstructionCode::INT_8.into(),
1544 2,
1545 InstructionCode::INT_8.into(),
1546 42,
1547 InstructionCode::SCOPE_END.into(),
1548 ];
1549 assert_eq!(result, expected);
1550 }
1551
1552 #[test]
1554 fn test_multiple_key_value_pairs() {
1555 init_logger_debug();
1556 let datex_script = "key: 42, 4: 43, (1 + 2): 44";
1557 let result = compile_and_log(datex_script);
1558 let expected = vec![
1559 InstructionCode::TUPLE_START.into(),
1560 InstructionCode::KEY_VALUE_SHORT_TEXT.into(),
1561 3, b'k',
1563 b'e',
1564 b'y',
1565 InstructionCode::INT_8.into(),
1566 42,
1567 InstructionCode::KEY_VALUE_DYNAMIC.into(),
1568 InstructionCode::INT_8.into(),
1569 4,
1570 InstructionCode::INT_8.into(),
1571 43,
1572 InstructionCode::KEY_VALUE_DYNAMIC.into(),
1573 InstructionCode::ADD.into(),
1574 InstructionCode::INT_8.into(),
1575 1,
1576 InstructionCode::INT_8.into(),
1577 2,
1578 InstructionCode::INT_8.into(),
1579 44,
1580 InstructionCode::SCOPE_END.into(),
1581 ];
1582 assert_eq!(result, expected);
1583 }
1584
1585 #[test]
1587 fn test_key_value_with_parentheses() {
1588 init_logger_debug();
1589 let datex_script = "(key: 42)";
1590 let result = compile_and_log(datex_script);
1591 let expected = vec![
1592 InstructionCode::TUPLE_START.into(),
1593 InstructionCode::KEY_VALUE_SHORT_TEXT.into(),
1594 3, b'k',
1596 b'e',
1597 b'y',
1598 InstructionCode::INT_8.into(),
1599 42,
1600 InstructionCode::SCOPE_END.into(),
1601 ];
1602 assert_eq!(result, expected);
1603 }
1604
1605 #[test]
1607 fn test_empty_object() {
1608 init_logger_debug();
1609 let datex_script = "{}";
1610 let result = compile_and_log(datex_script);
1611 let expected: Vec<u8> = vec![
1612 InstructionCode::OBJECT_START.into(),
1613 InstructionCode::SCOPE_END.into(),
1614 ];
1615 assert_eq!(result, expected);
1616 }
1617
1618 #[test]
1620 fn test_single_key_value_object() {
1621 init_logger_debug();
1622 let datex_script = "{key: 42}";
1623 let result = compile_and_log(datex_script);
1624 let expected = vec![
1625 InstructionCode::OBJECT_START.into(),
1626 InstructionCode::KEY_VALUE_SHORT_TEXT.into(),
1627 3, b'k',
1629 b'e',
1630 b'y',
1631 InstructionCode::INT_8.into(),
1632 42,
1633 InstructionCode::SCOPE_END.into(),
1634 ];
1635 assert_eq!(result, expected);
1636 }
1637
1638 #[test]
1640 fn test_multi_key_value_object() {
1641 init_logger_debug();
1642 let datex_script = "{key1: 42, \"key2\": 43, 'key3': 44}";
1643 let result = compile_and_log(datex_script);
1644 let expected = vec![
1645 InstructionCode::OBJECT_START.into(),
1646 InstructionCode::KEY_VALUE_SHORT_TEXT.into(),
1647 4, b'k',
1649 b'e',
1650 b'y',
1651 b'1',
1652 InstructionCode::INT_8.into(),
1653 42,
1654 InstructionCode::KEY_VALUE_SHORT_TEXT.into(),
1655 4, b'k',
1657 b'e',
1658 b'y',
1659 b'2',
1660 InstructionCode::INT_8.into(),
1661 43,
1662 InstructionCode::KEY_VALUE_SHORT_TEXT.into(),
1663 4, b'k',
1665 b'e',
1666 b'y',
1667 b'3',
1668 InstructionCode::INT_8.into(),
1669 44,
1670 InstructionCode::SCOPE_END.into(),
1671 ];
1672 assert_eq!(result, expected);
1673 }
1674
1675 #[test]
1676 fn test_allocate_slot() {
1677 init_logger_debug();
1678 let script = "const a = 42";
1679 let result = compile_and_log(script);
1680 assert_eq!(
1681 result,
1682 vec![
1683 InstructionCode::ALLOCATE_SLOT.into(),
1684 0,
1686 0,
1687 0,
1688 0,
1689 InstructionCode::INT_8.into(),
1690 42,
1691 InstructionCode::SCOPE_END.into(),
1692 ]
1693 );
1694 }
1695
1696 #[test]
1697 fn test_allocate_slot_with_value() {
1698 init_logger_debug();
1699 let script = "const a = 42; a + 1";
1700 let result = compile_and_log(script);
1701 assert_eq!(
1702 result,
1703 vec![
1704 InstructionCode::ALLOCATE_SLOT.into(),
1705 0,
1707 0,
1708 0,
1709 0,
1710 InstructionCode::INT_8.into(),
1711 42,
1712 InstructionCode::SCOPE_END.into(),
1713 InstructionCode::CLOSE_AND_STORE.into(),
1714 InstructionCode::ADD.into(),
1715 InstructionCode::GET_SLOT.into(),
1716 0,
1718 0,
1719 0,
1720 0,
1721 InstructionCode::INT_8.into(),
1722 1,
1723 ]
1724 );
1725 }
1726
1727 #[test]
1728 fn test_allocate_scoped_slots() {
1729 init_logger_debug();
1730 let script = "const a = 42; (const a = 43; a); a";
1731 let result = compile_and_log(script);
1732 assert_eq!(
1733 result,
1734 vec![
1735 InstructionCode::ALLOCATE_SLOT.into(),
1736 0,
1737 0,
1738 0,
1739 0,
1740 InstructionCode::INT_8.into(),
1741 42,
1742 InstructionCode::SCOPE_END.into(),
1743 InstructionCode::CLOSE_AND_STORE.into(),
1744 InstructionCode::SCOPE_START.into(),
1745 InstructionCode::ALLOCATE_SLOT.into(),
1746 1,
1747 0,
1748 0,
1749 0,
1750 InstructionCode::INT_8.into(),
1751 43,
1752 InstructionCode::SCOPE_END.into(),
1753 InstructionCode::CLOSE_AND_STORE.into(),
1754 InstructionCode::GET_SLOT.into(),
1755 1,
1756 0,
1757 0,
1758 0,
1759 InstructionCode::DROP_SLOT.into(),
1760 1,
1761 0,
1762 0,
1763 0,
1764 InstructionCode::SCOPE_END.into(),
1765 InstructionCode::CLOSE_AND_STORE.into(),
1766 InstructionCode::GET_SLOT.into(),
1767 0,
1769 0,
1770 0,
1771 0,
1772 ]
1773 );
1774 }
1775
1776 #[test]
1777 fn test_allocate_scoped_slots_with_parent_variables() {
1778 init_logger_debug();
1779 let script = "const a = 42; const b = 41; (const a = 43; a; b); a";
1780 let result = compile_and_log(script);
1781 assert_eq!(
1782 result,
1783 vec![
1784 InstructionCode::ALLOCATE_SLOT.into(),
1785 0,
1786 0,
1787 0,
1788 0,
1789 InstructionCode::INT_8.into(),
1790 42,
1791 InstructionCode::SCOPE_END.into(),
1792 InstructionCode::CLOSE_AND_STORE.into(),
1793 InstructionCode::ALLOCATE_SLOT.into(),
1794 1,
1795 0,
1796 0,
1797 0,
1798 InstructionCode::INT_8.into(),
1799 41,
1800 InstructionCode::SCOPE_END.into(),
1801 InstructionCode::CLOSE_AND_STORE.into(),
1802 InstructionCode::SCOPE_START.into(),
1803 InstructionCode::ALLOCATE_SLOT.into(),
1804 2,
1805 0,
1806 0,
1807 0,
1808 InstructionCode::INT_8.into(),
1809 43,
1810 InstructionCode::SCOPE_END.into(),
1811 InstructionCode::CLOSE_AND_STORE.into(),
1812 InstructionCode::GET_SLOT.into(),
1813 2,
1814 0,
1815 0,
1816 0,
1817 InstructionCode::CLOSE_AND_STORE.into(),
1818 InstructionCode::GET_SLOT.into(),
1819 1,
1820 0,
1821 0,
1822 0,
1823 InstructionCode::DROP_SLOT.into(),
1824 2,
1825 0,
1826 0,
1827 0,
1828 InstructionCode::SCOPE_END.into(),
1829 InstructionCode::CLOSE_AND_STORE.into(),
1830 InstructionCode::GET_SLOT.into(),
1831 0,
1833 0,
1834 0,
1835 0,
1836 ]
1837 );
1838 }
1839
1840 #[test]
1841 fn test_allocate_ref() {
1842 init_logger_debug();
1843 let script = "const mut a = 42";
1844 let result = compile_and_log(script);
1845 assert_eq!(
1846 result,
1847 vec![
1848 InstructionCode::ALLOCATE_SLOT.into(),
1849 0,
1851 0,
1852 0,
1853 0,
1854 InstructionCode::CREATE_REF.into(),
1855 InstructionCode::INT_8.into(),
1856 42,
1857 InstructionCode::SCOPE_END.into(),
1858 ]
1859 );
1860 }
1861
1862 #[test]
1863 fn test_read_ref() {
1864 init_logger_debug();
1865 let script = "const mut a = 42; a";
1866 let result = compile_and_log(script);
1867 assert_eq!(
1868 result,
1869 vec![
1870 InstructionCode::ALLOCATE_SLOT.into(),
1871 0,
1873 0,
1874 0,
1875 0,
1876 InstructionCode::CREATE_REF.into(),
1877 InstructionCode::INT_8.into(),
1878 42,
1879 InstructionCode::SCOPE_END.into(),
1880 InstructionCode::CLOSE_AND_STORE.into(),
1881 InstructionCode::GET_SLOT.into(),
1882 0,
1884 0,
1885 0,
1886 0,
1887 ]
1888 );
1889 }
1890
1891 #[test]
1892 fn test_compile() {
1893 init_logger_debug();
1894 let result = compile_template(
1895 "? + ?",
1896 &[1.into(), 2.into()],
1897 CompileOptions::default(),
1898 );
1899 assert_eq!(
1900 result.unwrap().0,
1901 vec![
1902 InstructionCode::ADD.into(),
1903 InstructionCode::INT_8.into(),
1904 1,
1905 InstructionCode::INT_8.into(),
1906 2
1907 ]
1908 );
1909 }
1910
1911 #[test]
1912 fn test_compile_macro() {
1913 init_logger_debug();
1914 let a = 1;
1915 let result = compile!("?", a);
1916 assert_eq!(result.unwrap().0, vec![InstructionCode::INT_8.into(), 1,]);
1917 }
1918
1919 #[test]
1920 fn test_compile_macro_multi() {
1921 init_logger_debug();
1922 let result = compile!("? + ?", 1, 2);
1923 assert_eq!(
1924 result.unwrap().0,
1925 vec![
1926 InstructionCode::ADD.into(),
1927 InstructionCode::INT_8.into(),
1928 1,
1929 InstructionCode::INT_8.into(),
1930 2
1931 ]
1932 );
1933 }
1934
1935 fn get_json_test_string(file_path: &str) -> String {
1936 let file_path = format!("benches/json/{file_path}");
1938 let file_path = std::path::Path::new(&file_path);
1939 let file =
1940 std::fs::File::open(file_path).expect("Failed to open test.json");
1941 let mut reader = std::io::BufReader::new(file);
1942 let mut json_string = String::new();
1943 reader
1944 .read_to_string(&mut json_string)
1945 .expect("Failed to read test.json");
1946 json_string
1947 }
1948
1949 #[test]
1950 fn test_json_to_dxb_large_file() {
1951 let json = get_json_test_string("test2.json");
1952 println!("JSON file read");
1953 let (dxb, _) = compile_script(&json, CompileOptions::default())
1954 .expect("Failed to parse JSON string");
1955 println!("DXB: {:?}", dxb.len());
1956 }
1957
1958 #[test]
1959 fn test_static_value_detection() {
1960 init_logger_debug();
1961
1962 let script = "1 + 2";
1964 let compilation_scope = get_compilation_scope(script);
1965 assert!(*compilation_scope.has_non_static_value.borrow());
1966
1967 let script = "1 2";
1968 let compilation_scope = get_compilation_scope(script);
1969 assert!(*compilation_scope.has_non_static_value.borrow());
1970
1971 let script = "1;2";
1972 let compilation_scope = get_compilation_scope(script);
1973 assert!(*compilation_scope.has_non_static_value.borrow());
1974
1975 let script = r#"{("x" + "y"): 1}"#;
1976 let compilation_scope = get_compilation_scope(script);
1977 assert!(*compilation_scope.has_non_static_value.borrow());
1978
1979 let script = "1";
1981 let compilation_scope = get_compilation_scope(script);
1982 assert!(!*compilation_scope.has_non_static_value.borrow());
1983
1984 let script = "[]";
1985 let compilation_scope = get_compilation_scope(script);
1986 assert!(!*compilation_scope.has_non_static_value.borrow());
1987
1988 let script = "{}";
1989 let compilation_scope = get_compilation_scope(script);
1990 assert!(!*compilation_scope.has_non_static_value.borrow());
1991
1992 let script = "[1,2,3]";
1993 let compilation_scope = get_compilation_scope(script);
1994 assert!(!*compilation_scope.has_non_static_value.borrow());
1995
1996 let script = "{a: 2}";
1997 let compilation_scope = get_compilation_scope(script);
1998 assert!(!*compilation_scope.has_non_static_value.borrow());
1999 }
2000
2001 #[test]
2002 fn test_compile_auto_static_value_detection() {
2003 let script = "1";
2004 let (res, _) = compile_script_or_return_static_value(
2005 script,
2006 CompileOptions::default(),
2007 )
2008 .unwrap();
2009 assert_eq!(
2010 res,
2011 StaticValueOrDXB::StaticValue(Some(Integer::from(1).into()))
2012 );
2013
2014 let script = "1 + 2";
2015 let (res, _) = compile_script_or_return_static_value(
2016 script,
2017 CompileOptions::default(),
2018 )
2019 .unwrap();
2020 assert_eq!(
2021 res,
2022 StaticValueOrDXB::Dxb(vec![
2023 InstructionCode::ADD.into(),
2024 InstructionCode::INT_8.into(),
2025 1,
2026 InstructionCode::INT_8.into(),
2027 2,
2028 ])
2029 );
2030 }
2031
2032 #[test]
2033 fn test_remote_execution() {
2034 let script = "42 :: 43";
2035 let (res, _) =
2036 compile_script(script, CompileOptions::default()).unwrap();
2037 assert_eq!(
2038 res,
2039 vec![
2040 InstructionCode::REMOTE_EXECUTION.into(),
2041 InstructionCode::INT_8.into(),
2043 42,
2044 InstructionCode::EXECUTION_BLOCK.into(),
2046 2,
2048 0,
2049 0,
2050 0,
2051 0,
2053 0,
2054 0,
2055 0,
2056 InstructionCode::INT_8.into(),
2058 43,
2059 ]
2060 );
2061 }
2062
2063 #[test]
2064 fn test_remote_execution_expression() {
2065 let script = "42 :: 1 + 2";
2066 let (res, _) =
2067 compile_script(script, CompileOptions::default()).unwrap();
2068 assert_eq!(
2069 res,
2070 vec![
2071 InstructionCode::REMOTE_EXECUTION.into(),
2072 InstructionCode::INT_8.into(),
2074 42,
2075 InstructionCode::EXECUTION_BLOCK.into(),
2077 5,
2079 0,
2080 0,
2081 0,
2082 0,
2084 0,
2085 0,
2086 0,
2087 InstructionCode::ADD.into(),
2089 InstructionCode::INT_8.into(),
2090 1,
2091 InstructionCode::INT_8.into(),
2092 2,
2093 ]
2094 );
2095 }
2096
2097 #[test]
2098 fn test_remote_execution_injected_const() {
2099 init_logger_debug();
2100 let script = "const x = 42; 1 :: x";
2101 let (res, _) =
2102 compile_script(script, CompileOptions::default()).unwrap();
2103 assert_eq!(
2104 res,
2105 vec![
2106 InstructionCode::ALLOCATE_SLOT.into(),
2107 0,
2109 0,
2110 0,
2111 0,
2112 InstructionCode::INT_8.into(),
2113 42,
2114 InstructionCode::SCOPE_END.into(),
2115 InstructionCode::CLOSE_AND_STORE.into(),
2116 InstructionCode::REMOTE_EXECUTION.into(),
2117 InstructionCode::INT_8.into(),
2119 1,
2120 InstructionCode::EXECUTION_BLOCK.into(),
2122 5,
2124 0,
2125 0,
2126 0,
2127 1,
2129 0,
2130 0,
2131 0,
2132 0,
2134 0,
2135 0,
2136 0,
2137 InstructionCode::GET_SLOT.into(),
2139 0,
2141 0,
2142 0,
2143 0,
2144 ]
2145 );
2146 }
2147
2148 #[test]
2149 fn test_remote_execution_injected_var() {
2150 init_logger_debug();
2151 let script = "var x = 42; 1 :: x; x = 43;";
2154 let (res, _) =
2155 compile_script(script, CompileOptions::default()).unwrap();
2156 assert_eq!(
2157 res,
2158 vec![
2159 InstructionCode::ALLOCATE_SLOT.into(),
2160 0,
2162 0,
2163 0,
2164 0,
2165 InstructionCode::INT_8.into(),
2166 42,
2167 InstructionCode::SCOPE_END.into(),
2168 InstructionCode::ALLOCATE_SLOT.into(),
2169 1,
2171 0,
2172 0,
2173 0,
2174 InstructionCode::CREATE_REF.into(),
2176 InstructionCode::GET_SLOT.into(),
2178 0,
2180 0,
2181 0,
2182 0,
2183 InstructionCode::SCOPE_END.into(),
2184 InstructionCode::CLOSE_AND_STORE.into(),
2185 InstructionCode::REMOTE_EXECUTION.into(),
2186 InstructionCode::INT_8.into(),
2188 1,
2189 InstructionCode::EXECUTION_BLOCK.into(),
2191 5,
2193 0,
2194 0,
2195 0,
2196 1,
2198 0,
2199 0,
2200 0,
2201 0,
2203 0,
2204 0,
2205 0,
2206 InstructionCode::GET_SLOT.into(),
2208 0,
2210 0,
2211 0,
2212 0,
2213 InstructionCode::CLOSE_AND_STORE.into(),
2214 InstructionCode::SET_SLOT.into(),
2217 0,
2219 0,
2220 0,
2221 0,
2222 InstructionCode::INT_8.into(),
2223 43,
2224 InstructionCode::SCOPE_END.into(),
2225 InstructionCode::CLOSE_AND_STORE.into(),
2226 ]
2227 );
2228 }
2229
2230 #[test]
2231 fn test_remote_execution_injected_consts() {
2232 let script = "const x = 42; const y = 69; 1 :: x + y";
2233 let (res, _) =
2234 compile_script(script, CompileOptions::default()).unwrap();
2235 assert_eq!(
2236 res,
2237 vec![
2238 InstructionCode::ALLOCATE_SLOT.into(),
2239 0,
2241 0,
2242 0,
2243 0,
2244 InstructionCode::INT_8.into(),
2245 42,
2246 InstructionCode::SCOPE_END.into(),
2247 InstructionCode::CLOSE_AND_STORE.into(),
2248 InstructionCode::ALLOCATE_SLOT.into(),
2249 1,
2251 0,
2252 0,
2253 0,
2254 InstructionCode::INT_8.into(),
2255 69,
2256 InstructionCode::SCOPE_END.into(),
2257 InstructionCode::CLOSE_AND_STORE.into(),
2258 InstructionCode::REMOTE_EXECUTION.into(),
2259 InstructionCode::INT_8.into(),
2261 1,
2262 InstructionCode::EXECUTION_BLOCK.into(),
2264 11,
2266 0,
2267 0,
2268 0,
2269 2,
2271 0,
2272 0,
2273 0,
2274 0,
2276 0,
2277 0,
2278 0,
2279 1,
2281 0,
2282 0,
2283 0,
2284 InstructionCode::ADD.into(),
2286 InstructionCode::GET_SLOT.into(),
2287 0,
2289 0,
2290 0,
2291 0,
2292 InstructionCode::GET_SLOT.into(),
2293 1,
2295 0,
2296 0,
2297 0,
2298 ]
2299 );
2300 }
2301
2302 #[test]
2303 fn test_remote_execution_shadow_const() {
2304 let script = "const x = 42; const y = 69; 1 :: (const x = 5; x + y)";
2305 let (res, _) =
2306 compile_script(script, CompileOptions::default()).unwrap();
2307 assert_eq!(
2308 res,
2309 vec![
2310 InstructionCode::ALLOCATE_SLOT.into(),
2311 0,
2313 0,
2314 0,
2315 0,
2316 InstructionCode::INT_8.into(),
2317 42,
2318 InstructionCode::SCOPE_END.into(),
2319 InstructionCode::CLOSE_AND_STORE.into(),
2320 InstructionCode::ALLOCATE_SLOT.into(),
2321 1,
2323 0,
2324 0,
2325 0,
2326 InstructionCode::INT_8.into(),
2327 69,
2328 InstructionCode::SCOPE_END.into(),
2329 InstructionCode::CLOSE_AND_STORE.into(),
2330 InstructionCode::REMOTE_EXECUTION.into(),
2331 InstructionCode::INT_8.into(),
2333 1,
2334 InstructionCode::EXECUTION_BLOCK.into(),
2336 20,
2338 0,
2339 0,
2340 0,
2341 1,
2343 0,
2344 0,
2345 0,
2346 1,
2348 0,
2349 0,
2350 0,
2351 InstructionCode::ALLOCATE_SLOT.into(),
2353 1,
2355 0,
2356 0,
2357 0,
2358 InstructionCode::INT_8.into(),
2359 5,
2360 InstructionCode::SCOPE_END.into(),
2361 InstructionCode::CLOSE_AND_STORE.into(),
2362 InstructionCode::ADD.into(),
2364 InstructionCode::GET_SLOT.into(),
2365 1,
2367 0,
2368 0,
2369 0,
2370 InstructionCode::GET_SLOT.into(),
2371 0,
2373 0,
2374 0,
2375 0,
2376 ]
2377 );
2378 }
2379
2380 #[test]
2381 fn test_remote_execution_nested() {
2382 let script = "const x = 42; (1 :: (2 :: x))";
2383 let (res, _) =
2384 compile_script(script, CompileOptions::default()).unwrap();
2385
2386 assert_eq!(
2387 res,
2388 vec![
2389 InstructionCode::ALLOCATE_SLOT.into(),
2390 0,
2392 0,
2393 0,
2394 0,
2395 InstructionCode::INT_8.into(),
2396 42,
2397 InstructionCode::SCOPE_END.into(),
2398 InstructionCode::CLOSE_AND_STORE.into(),
2399 InstructionCode::REMOTE_EXECUTION.into(),
2400 InstructionCode::INT_8.into(),
2402 1,
2403 InstructionCode::EXECUTION_BLOCK.into(),
2405 21,
2407 0,
2408 0,
2409 0,
2410 1,
2412 0,
2413 0,
2414 0,
2415 0,
2417 0,
2418 0,
2419 0,
2420 InstructionCode::REMOTE_EXECUTION.into(),
2422 InstructionCode::INT_8.into(),
2424 2,
2425 InstructionCode::EXECUTION_BLOCK.into(),
2427 5,
2429 0,
2430 0,
2431 0,
2432 1,
2434 0,
2435 0,
2436 0,
2437 0,
2439 0,
2440 0,
2441 0,
2442 InstructionCode::GET_SLOT.into(),
2443 0,
2445 0,
2446 0,
2447 0,
2448 ]
2449 );
2450 }
2451
2452 #[test]
2453 fn test_remote_execution_nested2() {
2454 let script = "const x = 42; (1 :: (x :: x))";
2455 let (res, _) =
2456 compile_script(script, CompileOptions::default()).unwrap();
2457
2458 assert_eq!(
2459 res,
2460 vec![
2461 InstructionCode::ALLOCATE_SLOT.into(),
2462 0,
2464 0,
2465 0,
2466 0,
2467 InstructionCode::INT_8.into(),
2468 42,
2469 InstructionCode::SCOPE_END.into(),
2470 InstructionCode::CLOSE_AND_STORE.into(),
2471 InstructionCode::REMOTE_EXECUTION.into(),
2472 InstructionCode::INT_8.into(),
2474 1,
2475 InstructionCode::EXECUTION_BLOCK.into(),
2477 24,
2479 0,
2480 0,
2481 0,
2482 1,
2484 0,
2485 0,
2486 0,
2487 0,
2489 0,
2490 0,
2491 0,
2492 InstructionCode::REMOTE_EXECUTION.into(),
2494 InstructionCode::GET_SLOT.into(),
2496 0,
2497 0,
2498 0,
2499 0,
2500 InstructionCode::EXECUTION_BLOCK.into(),
2502 5,
2504 0,
2505 0,
2506 0,
2507 1,
2509 0,
2510 0,
2511 0,
2512 0,
2514 0,
2515 0,
2516 0,
2517 InstructionCode::GET_SLOT.into(),
2518 0,
2520 0,
2521 0,
2522 0,
2523 ]
2524 );
2525 }
2526
2527 #[test]
2528 fn test_assignment_to_const() {
2529 init_logger_debug();
2530 let script = "const a = 42; a = 43";
2531 let result = compile_script(script, CompileOptions::default());
2532 assert_matches!(
2533 result,
2534 Err(CompilerError::AssignmentToConst { .. })
2535 );
2536 }
2537
2538 #[test]
2539 fn test_assignment_to_const_mut() {
2540 init_logger_debug();
2541 let script = "const mut a = 42; a = 43";
2542 let result = compile_script(script, CompileOptions::default());
2543 assert_matches!(
2544 result,
2545 Err(CompilerError::AssignmentToConst { .. })
2546 );
2547 }
2548
2549 #[test]
2550 fn test_slot_endpoint() {
2551 let script = "#endpoint";
2552 let (res, _) =
2553 compile_script(script, CompileOptions::default()).unwrap();
2554 assert_eq!(
2555 res,
2556 vec![
2557 InstructionCode::GET_SLOT.into(),
2558 0, 0xff, 0xff, 0xff
2560 ]
2561 );
2562 }
2563}