1use crate::ast::assignment_operation::AssignmentOperator;
2use crate::ast::binding::VariableId;
3use crate::compiler::error::CompilerError;
4use crate::global::dxb_block::DXBBlock;
5use crate::global::protocol_structures::block_header::BlockHeader;
6use crate::global::protocol_structures::encrypted_header::EncryptedHeader;
7use crate::global::protocol_structures::routing_header::RoutingHeader;
8
9use crate::ast::{DatexExpression, DatexScriptParser, VariableKind, parse};
10use crate::compiler::context::{CompilationContext, VirtualSlot};
11use crate::compiler::metadata::CompileMetadata;
12use crate::compiler::precompiler::{
13 AstMetadata, AstWithMetadata, VariableMetadata, precompile_ast,
14};
15use crate::compiler::scope::CompilationScope;
16use crate::compiler::type_compiler::compile_type_expression;
17use crate::global::instruction_codes::InstructionCode;
18use crate::global::slots::InternalSlot;
19use crate::libs::core::CoreLibPointerId;
20use crate::values::core_values::decimal::Decimal;
21use crate::values::pointer::PointerAddress;
22use crate::values::value_container::ValueContainer;
23use datex_core::ast::Slot;
24use log::info;
25use std::cell::RefCell;
26use std::rc::Rc;
27
28pub mod context;
29pub mod error;
30pub mod metadata;
31mod precompiler;
32pub mod scope;
33mod type_compiler;
34mod type_inference;
35
36#[derive(Clone, Default)]
37pub struct CompileOptions<'a> {
38 pub parser: Option<&'a DatexScriptParser<'a>>,
39 pub compile_scope: CompilationScope,
40}
41
42impl CompileOptions<'_> {
43 pub fn new_with_scope(compile_scope: CompilationScope) -> Self {
44 CompileOptions {
45 parser: None,
46 compile_scope,
47 }
48 }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub enum StaticValueOrDXB {
53 StaticValue(Option<ValueContainer>),
54 Dxb(Vec<u8>),
55}
56
57impl From<Vec<u8>> for StaticValueOrDXB {
58 fn from(dxb: Vec<u8>) -> Self {
59 StaticValueOrDXB::Dxb(dxb)
60 }
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Copy)]
64pub enum VariableModel {
65 Constant,
68 VariableSlot,
71 VariableReference,
75}
76
77impl From<VariableRepresentation> for VariableModel {
78 fn from(value: VariableRepresentation) -> Self {
79 match value {
80 VariableRepresentation::Constant(_) => VariableModel::Constant,
81 VariableRepresentation::VariableSlot(_) => {
82 VariableModel::VariableSlot
83 }
84 VariableRepresentation::VariableReference { .. } => {
85 VariableModel::VariableReference
86 }
87 }
88 }
89}
90
91impl VariableModel {
92 pub fn infer(
94 variable_kind: VariableKind,
95 variable_metadata: Option<VariableMetadata>,
96 is_end_of_source_text: bool,
97 ) -> Self {
98 if variable_kind == VariableKind::Const {
100 VariableModel::Constant
101 }
102 else if variable_metadata.is_none()
107 || variable_metadata.unwrap().is_cross_realm
108 || !is_end_of_source_text
109 {
110 VariableModel::VariableReference
111 }
112 else {
114 VariableModel::VariableSlot
115 }
116 }
117
118 pub fn infer_from_ast_metadata_and_type(
119 ast_metadata: &AstMetadata,
120 variable_id: Option<VariableId>,
121 variable_kind: VariableKind,
122 is_end_of_source_text: bool,
123 ) -> Self {
124 let variable_metadata =
125 variable_id.and_then(|id| ast_metadata.variable_metadata(id));
126 Self::infer(
127 variable_kind,
128 variable_metadata.cloned(),
129 is_end_of_source_text,
130 )
131 }
132}
133
134#[derive(Debug, Clone, PartialEq, Eq, Copy)]
135pub enum VariableRepresentation {
136 Constant(VirtualSlot),
137 VariableSlot(VirtualSlot),
138 VariableReference {
139 variable_slot: VirtualSlot,
141 container_slot: VirtualSlot,
143 },
144}
145
146#[derive(Debug, Clone)]
148pub struct Variable {
149 pub name: String,
150 pub kind: VariableKind,
151 pub representation: VariableRepresentation,
152}
153
154impl Variable {
155 pub fn new_const(name: String, slot: VirtualSlot) -> Self {
156 Variable {
157 name,
158 kind: VariableKind::Const,
159 representation: VariableRepresentation::Constant(slot),
160 }
161 }
162
163 pub fn new_variable_slot(
164 name: String,
165 kind: VariableKind,
166 slot: VirtualSlot,
167 ) -> Self {
168 Variable {
169 name,
170 kind,
171 representation: VariableRepresentation::VariableSlot(slot),
172 }
173 }
174
175 pub fn new_variable_reference(
176 name: String,
177 kind: VariableKind,
178 variable_slot: VirtualSlot,
179 container_slot: VirtualSlot,
180 ) -> Self {
181 Variable {
182 name,
183 kind,
184 representation: VariableRepresentation::VariableReference {
185 variable_slot,
186 container_slot,
187 },
188 }
189 }
190
191 pub fn slots(&self) -> Vec<VirtualSlot> {
192 match &self.representation {
193 VariableRepresentation::Constant(slot) => vec![*slot],
194 VariableRepresentation::VariableSlot(slot) => vec![*slot],
195 VariableRepresentation::VariableReference {
196 variable_slot,
197 container_slot,
198 } => {
199 vec![*variable_slot, *container_slot]
200 }
201 }
202 }
203}
204
205pub fn compile_block(datex_script: &str) -> Result<Vec<u8>, CompilerError> {
208 let (body, _) = compile_script(datex_script, CompileOptions::default())?;
209
210 let routing_header = RoutingHeader::default();
211
212 let block_header = BlockHeader::default();
213 let encrypted_header = EncryptedHeader::default();
214
215 let block =
216 DXBBlock::new(routing_header, block_header, encrypted_header, body);
217
218 let bytes = block
219 .to_bytes()
220 .map_err(CompilerError::SerializationError)?;
221 Ok(bytes)
222}
223
224pub fn compile_script<'a>(
226 datex_script: &'a str,
227 options: CompileOptions<'a>,
228) -> Result<(Vec<u8>, CompilationScope), CompilerError> {
229 compile_template(datex_script, &[], options)
230}
231
232pub fn extract_static_value_from_script(
236 datex_script: &str,
237) -> Result<Option<ValueContainer>, CompilerError> {
238 let res = parse(datex_script)?;
239 extract_static_value_from_ast(res).map(Some)
240}
241
242pub fn compile_template_with_refs<'a>(
245 datex_script: &'a str,
246 inserted_values: &[&ValueContainer],
247 options: CompileOptions<'a>,
248) -> Result<(Vec<u8>, CompilationScope), CompilerError> {
249 compile_template_or_return_static_value_with_refs(
250 datex_script,
251 inserted_values,
252 false,
253 options,
254 )
255 .map(|result| match result.0 {
256 StaticValueOrDXB::StaticValue(_) => unreachable!(),
257 StaticValueOrDXB::Dxb(dxb) => (dxb, result.1),
258 })
259}
260
261pub fn compile_script_or_return_static_value<'a>(
265 datex_script: &'a str,
266 options: CompileOptions<'a>,
267) -> Result<(StaticValueOrDXB, CompilationScope), CompilerError> {
268 compile_template_or_return_static_value_with_refs(
269 datex_script,
270 &[],
271 true,
272 options,
273 )
274}
275pub fn compile_template_or_return_static_value_with_refs<'a>(
277 datex_script: &'a str,
278 inserted_values: &[&ValueContainer],
279 return_static_value: bool,
280 options: CompileOptions<'a>,
281) -> Result<(StaticValueOrDXB, CompilationScope), CompilerError> {
282 if datex_script == "?" {
284 if inserted_values.len() != 1 {
285 return Err(CompilerError::InvalidPlaceholderCount);
286 }
287 let result =
288 compile_value(inserted_values[0]).map(StaticValueOrDXB::from)?;
289 return Ok((result, options.compile_scope));
290 }
291
292 let ast = parse(datex_script)?;
293
294 let buffer = RefCell::new(Vec::with_capacity(256));
295 let compilation_context = CompilationContext::new(
296 buffer,
297 inserted_values,
298 options.compile_scope.once,
299 );
300 let scope =
301 compile_ast(&compilation_context, ast.clone(), options.compile_scope)?;
302 if return_static_value {
303 if !*compilation_context.has_non_static_value.borrow() {
304 if let Ok(value) = ValueContainer::try_from(&ast) {
305 return Ok((
306 StaticValueOrDXB::StaticValue(Some(value.clone())),
307 scope,
308 ));
309 }
310 Ok((StaticValueOrDXB::StaticValue(None), scope))
311 } else {
312 Ok((
314 StaticValueOrDXB::Dxb(compilation_context.buffer.take()),
315 scope,
316 ))
317 }
318 } else {
319 Ok((
321 StaticValueOrDXB::Dxb(compilation_context.buffer.take()),
322 scope,
323 ))
324 }
325}
326
327pub fn compile_template<'a>(
329 datex_script: &'a str,
330 inserted_values: &[ValueContainer],
331 options: CompileOptions<'a>,
332) -> Result<(Vec<u8>, CompilationScope), CompilerError> {
333 compile_template_with_refs(
334 datex_script,
335 &inserted_values.iter().collect::<Vec<_>>(),
336 options,
337 )
338}
339
340pub fn compile_value(value: &ValueContainer) -> Result<Vec<u8>, CompilerError> {
341 let buffer = RefCell::new(Vec::with_capacity(256));
342 let compilation_scope = CompilationContext::new(buffer, &[], true);
343
344 compilation_scope.insert_value_container(value);
345
346 Ok(compilation_scope.buffer.take())
347}
348
349fn extract_static_value_from_ast(
353 ast: DatexExpression,
354) -> Result<ValueContainer, CompilerError> {
355 if let DatexExpression::Placeholder = ast {
356 return Err(CompilerError::NonStaticValue);
357 }
358 ValueContainer::try_from(&ast).map_err(|_| CompilerError::NonStaticValue)
359}
360
361#[macro_export]
369macro_rules! compile {
370 ($fmt:literal $(, $arg:expr )* $(,)?) => {
371 {
372 let script: &str = $fmt.into();
373 let values: &[$crate::values::value_container::ValueContainer] = &[$($arg.into()),*];
374
375 $crate::compiler::compile_template(&script, values, $crate::compiler::CompileOptions::default())
376 }
377 }
378}
379
380pub fn compile_ast(
381 compilation_context: &CompilationContext,
382 ast: DatexExpression,
383 mut scope: CompilationScope,
384) -> Result<CompilationScope, CompilerError> {
385 if scope.once {
387 if scope.was_used {
388 return Err(CompilerError::OnceScopeUsedMultipleTimes);
389 }
390 scope.was_used = true;
392 }
393 let ast_with_metadata =
394 if let Some(precompiler_data) = &scope.precompiler_data {
395 precompile_ast(
397 ast,
398 precompiler_data.ast_metadata.clone(),
399 &mut precompiler_data.precompiler_scope_stack.borrow_mut(),
400 )?
401 } else {
402 AstWithMetadata::new_without_metadata(ast)
404 };
405
406 compile_ast_with_metadata(compilation_context, ast_with_metadata, scope)
407}
408
409pub fn compile_ast_with_metadata(
410 compilation_context: &CompilationContext,
411 ast_with_metadata: AstWithMetadata,
412 scope: CompilationScope,
413) -> Result<CompilationScope, CompilerError> {
414 let scope = compile_expression(
415 compilation_context,
416 ast_with_metadata,
417 CompileMetadata::outer(),
418 scope,
419 )?;
420
421 compilation_context.remap_virtual_slots();
423 Ok(scope)
424}
425
426fn compile_expression(
427 compilation_context: &CompilationContext,
428 ast_with_metadata: AstWithMetadata,
429 meta: CompileMetadata,
430 mut scope: CompilationScope,
431) -> Result<CompilationScope, CompilerError> {
432 let metadata = ast_with_metadata.metadata;
433 match ast_with_metadata.ast {
434 DatexExpression::Integer(int) => {
435 compilation_context
436 .insert_encoded_integer(&int.to_smallest_fitting());
437 }
438 DatexExpression::TypedInteger(typed_int) => {
439 compilation_context.insert_typed_integer(&typed_int);
440 }
441 DatexExpression::Decimal(decimal) => match &decimal {
442 Decimal::Finite(big_decimal) if big_decimal.is_integer() => {
443 if let Some(int) = big_decimal.to_i16() {
444 compilation_context.insert_float_as_i16(int);
445 } else if let Some(int) = big_decimal.to_i32() {
446 compilation_context.insert_float_as_i32(int);
447 } else {
448 compilation_context.insert_decimal(&decimal);
449 }
450 }
451 _ => {
452 compilation_context.insert_decimal(&decimal);
453 }
454 },
455 DatexExpression::TypedDecimal(typed_decimal) => {
456 compilation_context.insert_typed_decimal(&typed_decimal);
457 }
458 DatexExpression::Text(text) => {
459 compilation_context.insert_text(&text);
460 }
461 DatexExpression::Boolean(boolean) => {
462 compilation_context.insert_boolean(boolean);
463 }
464 DatexExpression::Endpoint(endpoint) => {
465 compilation_context.insert_endpoint(&endpoint);
466 }
467 DatexExpression::Null => {
468 compilation_context.append_instruction_code(InstructionCode::NULL);
469 }
470 DatexExpression::List(list) => {
471 compilation_context
472 .append_instruction_code(InstructionCode::LIST_START);
473 for item in list {
474 scope = compile_expression(
475 compilation_context,
476 AstWithMetadata::new(item, &metadata),
477 CompileMetadata::default(),
478 scope,
479 )?;
480 }
481 compilation_context
482 .append_instruction_code(InstructionCode::SCOPE_END);
483 }
484 DatexExpression::Map(map) => {
485 compilation_context
487 .append_instruction_code(InstructionCode::MAP_START);
488 for (key, value) in map {
489 scope = compile_key_value_entry(
490 compilation_context,
491 key,
492 value,
493 &metadata,
494 scope,
495 )?;
496 }
497 compilation_context
498 .append_instruction_code(InstructionCode::SCOPE_END);
499 }
500 DatexExpression::Placeholder => {
501 compilation_context.insert_value_container(
502 compilation_context
503 .inserted_values
504 .borrow()
505 .get(compilation_context.inserted_value_index.get())
506 .unwrap(),
507 );
508 compilation_context.inserted_value_index.update(|x| x + 1);
509 }
510
511 DatexExpression::Statements(mut statements) => {
513 compilation_context.mark_has_non_static_value();
514 if statements.len() == 1 && !statements[0].is_terminated {
516 scope = compile_expression(
517 compilation_context,
518 AstWithMetadata::new(
519 statements.remove(0).expression,
520 &metadata,
521 ),
522 CompileMetadata::default(),
523 scope,
524 )?;
525 } else {
526 let mut child_scope = if !meta.is_outer_context() {
528 compilation_context
529 .append_instruction_code(InstructionCode::SCOPE_START);
530 scope.push()
531 } else {
532 scope
533 };
534 for statement in statements {
535 child_scope = compile_expression(
536 compilation_context,
537 AstWithMetadata::new(statement.expression, &metadata),
538 CompileMetadata::default(),
539 child_scope,
540 )?;
541 if statement.is_terminated {
543 compilation_context.append_instruction_code(
544 InstructionCode::CLOSE_AND_STORE,
545 );
546 }
547 }
548 if !meta.is_outer_context() {
549 let scope_data = child_scope
550 .pop()
551 .ok_or(CompilerError::ScopePopError)?;
552 scope = scope_data.0; for slot_address in scope_data.1 {
555 compilation_context.append_instruction_code(
556 InstructionCode::DROP_SLOT,
557 );
558 compilation_context
560 .insert_virtual_slot_address(slot_address);
561 }
562 compilation_context
563 .append_instruction_code(InstructionCode::SCOPE_END);
564 } else {
565 scope = child_scope;
566 }
567 }
568 }
569
570 DatexExpression::UnaryOperation(operator, expr) => {
572 compilation_context
573 .append_instruction_code(InstructionCode::from(&operator));
574 scope = compile_expression(
575 compilation_context,
576 AstWithMetadata::new(*expr, &metadata),
577 CompileMetadata::default(),
578 scope,
579 )?;
580 }
581
582 DatexExpression::BinaryOperation(operator, a, b, _) => {
584 compilation_context.mark_has_non_static_value();
585 compilation_context
587 .append_instruction_code(InstructionCode::from(&operator));
588 scope = compile_expression(
589 compilation_context,
590 AstWithMetadata::new(*a, &metadata),
591 CompileMetadata::default(),
592 scope,
593 )?;
594 scope = compile_expression(
595 compilation_context,
596 AstWithMetadata::new(*b, &metadata),
597 CompileMetadata::default(),
598 scope,
599 )?;
600 }
601
602 DatexExpression::ComparisonOperation(operator, a, b) => {
604 compilation_context.mark_has_non_static_value();
605 compilation_context
607 .append_instruction_code(InstructionCode::from(&operator));
608 scope = compile_expression(
609 compilation_context,
610 AstWithMetadata::new(*a, &metadata),
611 CompileMetadata::default(),
612 scope,
613 )?;
614 scope = compile_expression(
615 compilation_context,
616 AstWithMetadata::new(*b, &metadata),
617 CompileMetadata::default(),
618 scope,
619 )?;
620 }
621
622 DatexExpression::ApplyChain(val, operands) => {
624 compilation_context.mark_has_non_static_value();
625 }
627
628 DatexExpression::VariableDeclaration {
631 id,
632 name,
633 kind,
634 type_annotation,
635 init_expression: value,
636 } => {
637 compilation_context.mark_has_non_static_value();
638
639 let virtual_slot_addr = scope.get_next_virtual_slot();
641 compilation_context
642 .append_instruction_code(InstructionCode::ALLOCATE_SLOT);
643 compilation_context.insert_virtual_slot_address(
644 VirtualSlot::local(virtual_slot_addr),
645 );
646 scope = compile_expression(
648 compilation_context,
649 AstWithMetadata::new(*value, &metadata),
650 CompileMetadata::default(),
651 scope,
652 )?;
653
654 let variable_model =
655 VariableModel::infer_from_ast_metadata_and_type(
656 &metadata.borrow(),
657 id,
658 kind,
659 compilation_context.is_end_of_source_text,
660 );
661 info!("variable model for {name}: {variable_model:?}");
662
663 let variable = match variable_model {
665 VariableModel::VariableReference => {
666 compilation_context
668 .append_instruction_code(InstructionCode::SCOPE_END);
669 let virtual_slot_addr_for_var =
671 scope.get_next_virtual_slot();
672 compilation_context.append_instruction_code(
673 InstructionCode::ALLOCATE_SLOT,
674 );
675 compilation_context.insert_virtual_slot_address(
676 VirtualSlot::local(virtual_slot_addr_for_var),
677 );
678 compilation_context
680 .append_instruction_code(InstructionCode::CREATE_REF);
681 compilation_context
683 .append_instruction_code(InstructionCode::GET_SLOT);
684 compilation_context.insert_virtual_slot_address(
685 VirtualSlot::local(virtual_slot_addr),
686 );
687
688 Variable::new_variable_reference(
689 name.clone(),
690 kind,
691 VirtualSlot::local(virtual_slot_addr_for_var),
692 VirtualSlot::local(virtual_slot_addr),
693 )
694 }
695 VariableModel::Constant => Variable::new_const(
696 name.clone(),
697 VirtualSlot::local(virtual_slot_addr),
698 ),
699 VariableModel::VariableSlot => Variable::new_variable_slot(
700 name.clone(),
701 kind,
702 VirtualSlot::local(virtual_slot_addr),
703 ),
704 };
705
706 scope.register_variable_slot(variable);
707
708 compilation_context
709 .append_instruction_code(InstructionCode::SCOPE_END);
710 }
711
712 DatexExpression::GetReference(address) => {
713 compilation_context.mark_has_non_static_value();
714 compilation_context.insert_get_ref(address);
715 }
716
717 DatexExpression::VariableAssignment(operator, id, name, expression) => {
719 compilation_context.mark_has_non_static_value();
720 let (virtual_slot, kind) = scope
722 .resolve_variable_name_to_virtual_slot(&name)
723 .ok_or_else(|| {
724 CompilerError::UndeclaredVariable(name.clone())
725 })?;
726
727 if kind == VariableKind::Const {
729 return Err(CompilerError::AssignmentToConst(name.clone()));
730 }
731
732 match operator {
733 AssignmentOperator::Assign => {
734 info!(
736 "append variable virtual slot: {virtual_slot:?}, name: {name}"
737 );
738 compilation_context
739 .append_instruction_code(InstructionCode::SET_SLOT);
740 }
744 AssignmentOperator::AddAssign
745 | AssignmentOperator::SubtractAssign => {
746 compilation_context
762 .append_instruction_code(InstructionCode::SET_SLOT);
763 compilation_context.append_instruction_code(
764 InstructionCode::from(&operator),
765 );
766 }
767 op => todo!("#436 Handle assignment operator: {op:?}"),
768 }
769
770 compilation_context.insert_virtual_slot_address(virtual_slot);
771 scope = compile_expression(
773 compilation_context,
774 AstWithMetadata::new(*expression, &metadata),
775 CompileMetadata::default(),
776 scope,
777 )?;
778 compilation_context
780 .append_instruction_code(InstructionCode::SCOPE_END);
781 }
782
783 DatexExpression::DerefAssignment {
784 operator,
785 deref_count,
786 deref_expression,
787 assigned_expression,
788 } => {
789 compilation_context.mark_has_non_static_value();
790
791 compilation_context
792 .append_instruction_code(InstructionCode::ASSIGN_TO_REF);
793
794 compilation_context
795 .append_instruction_code(InstructionCode::from(&operator));
796
797 for _ in 0..deref_count - 1 {
799 compilation_context
800 .append_instruction_code(InstructionCode::DEREF);
801 }
802
803 scope = compile_expression(
805 compilation_context,
806 AstWithMetadata::new(*deref_expression, &metadata),
807 CompileMetadata::default(),
808 scope,
809 )?;
810
811 for _ in 0..deref_count - 1 {
812 compilation_context
813 .append_instruction_code(InstructionCode::SCOPE_END);
814 }
815
816 scope = compile_expression(
818 compilation_context,
819 AstWithMetadata::new(*assigned_expression, &metadata),
820 CompileMetadata::default(),
821 scope,
822 )?;
823
824 compilation_context
826 .append_instruction_code(InstructionCode::SCOPE_END);
827 }
828
829 DatexExpression::Variable(id, name) => {
831 compilation_context.mark_has_non_static_value();
832 let (virtual_slot, ..) = scope
834 .resolve_variable_name_to_virtual_slot(&name)
835 .ok_or_else(|| {
836 CompilerError::UndeclaredVariable(name.clone())
837 })?;
838 compilation_context
840 .append_instruction_code(InstructionCode::GET_SLOT);
841 compilation_context.insert_virtual_slot_address(virtual_slot);
842 }
843
844 DatexExpression::RemoteExecution(caller, script) => {
846 compilation_context.mark_has_non_static_value();
847
848 compilation_context
850 .append_instruction_code(InstructionCode::REMOTE_EXECUTION);
851 scope = compile_expression(
853 compilation_context,
854 AstWithMetadata::new(*caller, &metadata),
855 CompileMetadata::default(),
856 scope,
857 )?;
858
859 let execution_block_ctx = CompilationContext::new(
861 RefCell::new(Vec::with_capacity(256)),
862 &[],
863 true,
864 );
865 let external_scope = compile_ast_with_metadata(
866 &execution_block_ctx,
867 AstWithMetadata::new(*script, &metadata),
868 CompilationScope::new_with_external_parent_scope(scope),
869 )?;
870 scope = external_scope
872 .pop_external()
873 .ok_or_else(|| CompilerError::ScopePopError)?;
874
875 let external_slots = execution_block_ctx.external_slots();
876 compilation_context
878 .append_instruction_code(InstructionCode::EXECUTION_BLOCK);
879 compilation_context
881 .append_u32(execution_block_ctx.buffer.borrow().len() as u32);
882 compilation_context.append_u32(external_slots.len() as u32);
884 for slot in external_slots {
885 compilation_context.insert_virtual_slot_address(slot.upgrade());
886 }
887
888 compilation_context
890 .append_buffer(&execution_block_ctx.buffer.borrow())
891 }
892
893 DatexExpression::Slot(Slot::Named(name)) => {
895 match name.as_str() {
896 "endpoint" => {
897 compilation_context
898 .append_instruction_code(InstructionCode::GET_SLOT);
899 compilation_context
900 .append_u32(InternalSlot::ENDPOINT as u32);
901 }
902 "core" => compilation_context.insert_get_ref(
903 PointerAddress::from(CoreLibPointerId::Core),
904 ),
905 _ => {
906 return Err(CompilerError::InvalidSlotName(name.clone()));
908 }
909 }
910 }
911
912 DatexExpression::PointerAddress(address) => {
914 compilation_context.insert_get_ref(address);
915 }
916
917 DatexExpression::CreateRef(expression) => {
919 compilation_context.mark_has_non_static_value();
920 compilation_context
921 .append_instruction_code(InstructionCode::CREATE_REF);
922 scope = compile_expression(
923 compilation_context,
924 AstWithMetadata::new(*expression, &metadata),
925 CompileMetadata::default(),
926 scope,
927 )?;
928 }
929 DatexExpression::CreateRefMut(expression) => {
930 compilation_context.mark_has_non_static_value();
931 compilation_context
932 .append_instruction_code(InstructionCode::CREATE_REF_MUT);
933 scope = compile_expression(
934 compilation_context,
935 AstWithMetadata::new(*expression, &metadata),
936 CompileMetadata::default(),
937 scope,
938 )?;
939 }
940 DatexExpression::CreateRefFinal(expression) => {
941 compilation_context.mark_has_non_static_value();
942 compilation_context
943 .append_instruction_code(InstructionCode::CREATE_REF_FINAL);
944 scope = compile_expression(
945 compilation_context,
946 AstWithMetadata::new(*expression, &metadata),
947 CompileMetadata::default(),
948 scope,
949 )?;
950 }
951
952 DatexExpression::Type(type_expression) => {
953 compilation_context
954 .append_instruction_code(InstructionCode::TYPE_EXPRESSION);
955 scope = compile_type_expression(
956 compilation_context,
957 &type_expression,
958 metadata,
959 scope,
960 )?;
961 }
962
963 DatexExpression::Deref(expression) => {
964 compilation_context.mark_has_non_static_value();
965 compilation_context.append_instruction_code(InstructionCode::DEREF);
966 scope = compile_expression(
967 compilation_context,
968 AstWithMetadata::new(*expression, &metadata),
969 CompileMetadata::default(),
970 scope,
971 )?;
972 compilation_context
973 .append_instruction_code(InstructionCode::SCOPE_END);
974 }
975
976 _ => {
977 return Err(CompilerError::UnexpectedTerm(Box::new(
978 ast_with_metadata.ast,
979 )));
980 }
981 }
982
983 Ok(scope)
984}
985
986fn compile_key_value_entry(
987 compilation_scope: &CompilationContext,
988 key: DatexExpression,
989 value: DatexExpression,
990 metadata: &Rc<RefCell<AstMetadata>>,
991 mut scope: CompilationScope,
992) -> Result<CompilationScope, CompilerError> {
993 match key {
994 DatexExpression::Text(text) => {
996 compilation_scope.insert_key_string(&text);
997 }
998 _ => {
1000 compilation_scope
1001 .append_instruction_code(InstructionCode::KEY_VALUE_DYNAMIC);
1002 scope = compile_expression(
1003 compilation_scope,
1004 AstWithMetadata::new(key, metadata),
1005 CompileMetadata::default(),
1006 scope,
1007 )?;
1008 }
1009 };
1010 scope = compile_expression(
1012 compilation_scope,
1013 AstWithMetadata::new(value, metadata),
1014 CompileMetadata::default(),
1015 scope,
1016 )?;
1017 Ok(scope)
1018}
1019
1020#[cfg(test)]
1021pub mod tests {
1022 use super::{
1023 CompilationContext, CompilationScope, CompileOptions, StaticValueOrDXB,
1024 compile_ast, compile_script, compile_script_or_return_static_value,
1025 compile_template,
1026 };
1027 use std::assert_matches::assert_matches;
1028 use std::cell::RefCell;
1029 use std::io::Read;
1030 use std::vec;
1031
1032 use crate::ast::parse;
1033 use crate::global::type_instruction_codes::TypeSpaceInstructionCode;
1034 use crate::libs::core::CoreLibPointerId;
1035 use crate::values::core_values::integer::Integer;
1036 use crate::values::pointer::PointerAddress;
1037 use crate::{
1038 global::instruction_codes::InstructionCode, logger::init_logger_debug,
1039 };
1040 use datex_core::compiler::error::CompilerError;
1041 use log::*;
1042
1043 fn compile_and_log(datex_script: &str) -> Vec<u8> {
1044 init_logger_debug();
1045 let (result, _) =
1046 compile_script(datex_script, CompileOptions::default()).unwrap();
1047 info!(
1048 "{:?}",
1049 result
1050 .iter()
1051 .map(|x| InstructionCode::try_from(*x).map(|x| x.to_string()))
1052 .map(|x| x.unwrap_or_else(|_| "Unknown".to_string()))
1053 .collect::<Vec<_>>()
1054 );
1055 result
1056 }
1057
1058 fn get_compilation_scope(script: &str) -> CompilationContext {
1059 let ast = parse(script);
1060 let ast = ast.unwrap();
1061 let buffer = RefCell::new(Vec::with_capacity(256));
1062 let compilation_scope = CompilationContext::new(buffer, &[], true);
1063 compile_ast(&compilation_scope, ast, CompilationScope::default())
1064 .unwrap();
1065 compilation_scope
1066 }
1067
1068 #[test]
1069 fn simple_multiplication() {
1070 init_logger_debug();
1071
1072 let lhs: u8 = 1;
1073 let rhs: u8 = 2;
1074 let datex_script = format!("{lhs} * {rhs}"); let result = compile_and_log(&datex_script);
1076 assert_eq!(
1077 result,
1078 vec![
1079 InstructionCode::MULTIPLY.into(),
1080 InstructionCode::INT_8.into(),
1081 lhs,
1082 InstructionCode::INT_8.into(),
1083 rhs,
1084 ]
1085 );
1086 }
1087
1088 #[test]
1089 fn simple_multiplication_close() {
1090 init_logger_debug();
1091
1092 let lhs: u8 = 1;
1093 let rhs: u8 = 2;
1094 let datex_script = format!("{lhs} * {rhs};"); let result = compile_and_log(&datex_script);
1096 assert_eq!(
1097 result,
1098 vec![
1099 InstructionCode::MULTIPLY.into(),
1100 InstructionCode::INT_8.into(),
1101 lhs,
1102 InstructionCode::INT_8.into(),
1103 rhs,
1104 InstructionCode::CLOSE_AND_STORE.into()
1105 ]
1106 );
1107 }
1108
1109 #[test]
1110 fn is_operator() {
1111 init_logger_debug();
1112
1113 let datex_script = "1 is 2".to_string();
1115 let result = compile_and_log(&datex_script);
1116 assert_eq!(
1117 result,
1118 vec![
1119 InstructionCode::IS.into(),
1120 InstructionCode::INT_8.into(),
1121 1,
1122 InstructionCode::INT_8.into(),
1123 2
1124 ]
1125 );
1126
1127 let datex_script =
1128 "const a = &mut 42; const b = &mut 69; a is b".to_string(); let result = compile_and_log(&datex_script);
1130 assert_eq!(
1131 result,
1132 vec![
1133 InstructionCode::ALLOCATE_SLOT.into(),
1135 0,
1136 0,
1137 0,
1138 0,
1139 InstructionCode::CREATE_REF_MUT.into(),
1140 InstructionCode::INT_8.into(),
1141 42,
1142 InstructionCode::SCOPE_END.into(),
1143 InstructionCode::CLOSE_AND_STORE.into(),
1144 InstructionCode::ALLOCATE_SLOT.into(),
1146 1,
1147 0,
1148 0,
1149 0,
1150 InstructionCode::CREATE_REF_MUT.into(),
1151 InstructionCode::INT_8.into(),
1152 69,
1153 InstructionCode::SCOPE_END.into(),
1154 InstructionCode::CLOSE_AND_STORE.into(),
1155 InstructionCode::IS.into(),
1157 InstructionCode::GET_SLOT.into(),
1158 0,
1159 0,
1160 0,
1161 0, InstructionCode::GET_SLOT.into(),
1163 1,
1164 0,
1165 0,
1166 0, ]
1168 );
1169 }
1170
1171 #[test]
1172 fn equality_operator() {
1173 init_logger_debug();
1174
1175 let lhs: u8 = 1;
1176 let rhs: u8 = 2;
1177 let datex_script = format!("{lhs} == {rhs}"); let result = compile_and_log(&datex_script);
1179 assert_eq!(
1180 result,
1181 vec![
1182 InstructionCode::STRUCTURAL_EQUAL.into(),
1183 InstructionCode::INT_8.into(),
1184 lhs,
1185 InstructionCode::INT_8.into(),
1186 rhs,
1187 ]
1188 );
1189
1190 let datex_script = format!("{lhs} === {rhs}"); let result = compile_and_log(&datex_script);
1192 assert_eq!(
1193 result,
1194 vec![
1195 InstructionCode::EQUAL.into(),
1196 InstructionCode::INT_8.into(),
1197 lhs,
1198 InstructionCode::INT_8.into(),
1199 rhs,
1200 ]
1201 );
1202
1203 let datex_script = format!("{lhs} != {rhs}"); let result = compile_and_log(&datex_script);
1205 assert_eq!(
1206 result,
1207 vec![
1208 InstructionCode::NOT_STRUCTURAL_EQUAL.into(),
1209 InstructionCode::INT_8.into(),
1210 lhs,
1211 InstructionCode::INT_8.into(),
1212 rhs,
1213 ]
1214 );
1215 let datex_script = format!("{lhs} !== {rhs}"); let result = compile_and_log(&datex_script);
1217 assert_eq!(
1218 result,
1219 vec![
1220 InstructionCode::NOT_EQUAL.into(),
1221 InstructionCode::INT_8.into(),
1222 lhs,
1223 InstructionCode::INT_8.into(),
1224 rhs,
1225 ]
1226 );
1227 }
1228
1229 #[test]
1230 fn simple_addition() {
1231 init_logger_debug();
1232
1233 let lhs: u8 = 1;
1234 let rhs: u8 = 2;
1235 let datex_script = format!("{lhs} + {rhs}"); let result = compile_and_log(&datex_script);
1237 assert_eq!(
1238 result,
1239 vec![
1240 InstructionCode::ADD.into(),
1241 InstructionCode::INT_8.into(),
1242 lhs,
1243 InstructionCode::INT_8.into(),
1244 rhs
1245 ]
1246 );
1247
1248 let datex_script = format!("{lhs} + {rhs};"); let result = compile_and_log(&datex_script);
1250 assert_eq!(
1251 result,
1252 vec![
1253 InstructionCode::ADD.into(),
1254 InstructionCode::INT_8.into(),
1255 lhs,
1256 InstructionCode::INT_8.into(),
1257 rhs,
1258 InstructionCode::CLOSE_AND_STORE.into()
1259 ]
1260 );
1261 }
1262
1263 #[test]
1264 fn multi_addition() {
1265 init_logger_debug();
1266
1267 let op1: u8 = 1;
1268 let op2: u8 = 2;
1269 let op3: u8 = 3;
1270 let op4: u8 = 4;
1271
1272 let datex_script = format!("{op1} + {op2} + {op3} + {op4}"); let result = compile_and_log(&datex_script);
1274 assert_eq!(
1275 result,
1276 vec![
1277 InstructionCode::ADD.into(),
1278 InstructionCode::ADD.into(),
1279 InstructionCode::ADD.into(),
1280 InstructionCode::INT_8.into(),
1281 op1,
1282 InstructionCode::INT_8.into(),
1283 op2,
1284 InstructionCode::INT_8.into(),
1285 op3,
1286 InstructionCode::INT_8.into(),
1287 op4,
1288 ]
1289 );
1290 }
1291
1292 #[test]
1293 fn mixed_calculation() {
1294 init_logger_debug();
1295
1296 let op1: u8 = 1;
1297 let op2: u8 = 2;
1298 let op3: u8 = 3;
1299 let op4: u8 = 4;
1300
1301 let datex_script = format!("{op1} * {op2} + {op3} * {op4}"); let result = compile_and_log(&datex_script);
1303 assert_eq!(
1304 result,
1305 vec![
1306 InstructionCode::ADD.into(),
1307 InstructionCode::MULTIPLY.into(),
1308 InstructionCode::INT_8.into(),
1309 op1,
1310 InstructionCode::INT_8.into(),
1311 op2,
1312 InstructionCode::MULTIPLY.into(),
1313 InstructionCode::INT_8.into(),
1314 op3,
1315 InstructionCode::INT_8.into(),
1316 op4,
1317 ]
1318 );
1319 }
1320
1321 #[test]
1322 fn complex_addition() {
1323 init_logger_debug();
1324
1325 let a: u8 = 1;
1326 let b: u8 = 2;
1327 let c: u8 = 3;
1328 let datex_script = format!("{a} + ({b} + {c})"); let result = compile_and_log(&datex_script);
1330
1331 assert_eq!(
1335 result,
1336 vec![
1337 InstructionCode::ADD.into(),
1338 InstructionCode::INT_8.into(),
1339 a,
1340 InstructionCode::ADD.into(),
1341 InstructionCode::INT_8.into(),
1342 b,
1343 InstructionCode::INT_8.into(),
1344 c,
1345 ]
1346 );
1347 }
1348
1349 #[test]
1350 fn complex_addition_and_subtraction() {
1351 init_logger_debug();
1352
1353 let a: u8 = 1;
1354 let b: u8 = 2;
1355 let c: u8 = 3;
1356 let datex_script = format!("{a} + ({b} - {c})"); let result = compile_and_log(&datex_script);
1358 assert_eq!(
1359 result,
1360 vec![
1361 InstructionCode::ADD.into(),
1362 InstructionCode::INT_8.into(),
1363 a,
1364 InstructionCode::SUBTRACT.into(),
1365 InstructionCode::INT_8.into(),
1366 b,
1367 InstructionCode::INT_8.into(),
1368 c,
1369 ]
1370 );
1371 }
1372
1373 #[test]
1374 fn integer_u8() {
1375 init_logger_debug();
1376 let val = 42;
1377 let datex_script = format!("{val}"); let result = compile_and_log(&datex_script);
1379 assert_eq!(result, vec![InstructionCode::INT_8.into(), val,]);
1380 }
1381
1382 #[test]
1384 fn decimal() {
1385 init_logger_debug();
1386 let datex_script = "42.0";
1387 let result = compile_and_log(datex_script);
1388 let bytes = 42_i16.to_le_bytes();
1389
1390 let mut expected: Vec<u8> =
1391 vec![InstructionCode::DECIMAL_AS_INT_16.into()];
1392 expected.extend(bytes);
1393
1394 assert_eq!(result, expected);
1395 }
1396
1397 #[test]
1399 fn short_text() {
1400 init_logger_debug();
1401 let val = "unyt";
1402 let datex_script = format!("\"{val}\""); let result = compile_and_log(&datex_script);
1404 let mut expected: Vec<u8> =
1405 vec![InstructionCode::SHORT_TEXT.into(), val.len() as u8];
1406 expected.extend(val.bytes());
1407 assert_eq!(result, expected);
1408 }
1409
1410 #[test]
1412 fn empty_list() {
1413 init_logger_debug();
1414 let datex_script = "[]";
1416 let result = compile_and_log(datex_script);
1418 let expected: Vec<u8> = vec![
1419 InstructionCode::LIST_START.into(),
1420 InstructionCode::SCOPE_END.into(),
1421 ];
1422 assert_eq!(result, expected);
1423 }
1424
1425 #[test]
1427 fn single_element_list() {
1428 init_logger_debug();
1429 let datex_script = "[42]";
1431 let result = compile_and_log(datex_script);
1432 assert_eq!(
1433 result,
1434 vec![
1435 InstructionCode::LIST_START.into(),
1436 InstructionCode::INT_8.into(),
1437 42,
1438 InstructionCode::SCOPE_END.into(),
1439 ]
1440 );
1441 }
1442
1443 #[test]
1445 fn multi_element_list() {
1446 init_logger_debug();
1447 let datex_script = "[1, 2, 3]";
1448 let result = compile_and_log(datex_script);
1449 assert_eq!(
1450 result,
1451 vec![
1452 InstructionCode::LIST_START.into(),
1453 InstructionCode::INT_8.into(),
1454 1,
1455 InstructionCode::INT_8.into(),
1456 2,
1457 InstructionCode::INT_8.into(),
1458 3,
1459 InstructionCode::SCOPE_END.into(),
1460 ]
1461 );
1462
1463 let datex_script = "[1, 2, 3,]";
1465 let result = compile_and_log(datex_script);
1466 assert_eq!(
1467 result,
1468 vec![
1469 InstructionCode::LIST_START.into(),
1470 InstructionCode::INT_8.into(),
1471 1,
1472 InstructionCode::INT_8.into(),
1473 2,
1474 InstructionCode::INT_8.into(),
1475 3,
1476 InstructionCode::SCOPE_END.into(),
1477 ]
1478 );
1479 }
1480
1481 #[test]
1483 fn list_with_expressions() {
1484 init_logger_debug();
1485 let datex_script = "[1 + 2, 3 * 4]";
1486 let result = compile_and_log(datex_script);
1487 assert_eq!(
1488 result,
1489 vec![
1490 InstructionCode::LIST_START.into(),
1491 InstructionCode::ADD.into(),
1492 InstructionCode::INT_8.into(),
1493 1,
1494 InstructionCode::INT_8.into(),
1495 2,
1496 InstructionCode::MULTIPLY.into(),
1497 InstructionCode::INT_8.into(),
1498 3,
1499 InstructionCode::INT_8.into(),
1500 4,
1501 InstructionCode::SCOPE_END.into(),
1502 ]
1503 );
1504 }
1505
1506 #[test]
1508 fn nested_lists() {
1509 init_logger_debug();
1510 let datex_script = "[1, [2, 3], 4]";
1511 let result = compile_and_log(datex_script);
1512 assert_eq!(
1513 result,
1514 vec![
1515 InstructionCode::LIST_START.into(),
1516 InstructionCode::INT_8.into(),
1517 1,
1518 InstructionCode::LIST_START.into(),
1519 InstructionCode::INT_8.into(),
1520 2,
1521 InstructionCode::INT_8.into(),
1522 3,
1523 InstructionCode::SCOPE_END.into(),
1524 InstructionCode::INT_8.into(),
1525 4,
1526 InstructionCode::SCOPE_END.into(),
1527 ]
1528 );
1529 }
1530
1531 #[test]
1533 fn map_with_text_key() {
1534 init_logger_debug();
1535 let datex_script = "{\"key\": 42}";
1536 let result = compile_and_log(datex_script);
1537 let expected = vec![
1538 InstructionCode::MAP_START.into(),
1539 InstructionCode::KEY_VALUE_SHORT_TEXT.into(),
1540 3, b'k',
1542 b'e',
1543 b'y',
1544 InstructionCode::INT_8.into(),
1545 42,
1546 InstructionCode::SCOPE_END.into(),
1547 ];
1548 assert_eq!(result, expected);
1549 }
1550
1551 #[test]
1553 fn map_integer_key() {
1554 init_logger_debug();
1555 let datex_script = "{(10): 42}";
1556 let result = compile_and_log(datex_script);
1557 let expected = vec![
1558 InstructionCode::MAP_START.into(),
1559 InstructionCode::KEY_VALUE_DYNAMIC.into(),
1560 InstructionCode::INT_8.into(),
1561 10,
1562 InstructionCode::INT_8.into(),
1563 42,
1564 InstructionCode::SCOPE_END.into(),
1565 ];
1566 assert_eq!(result, expected);
1567 }
1568
1569 #[test]
1571 fn map_with_long_text_key() {
1572 init_logger_debug();
1573 let long_key = "a".repeat(300);
1574 let datex_script = format!("{{\"{long_key}\": 42}}");
1575 let result = compile_and_log(&datex_script);
1576 let mut expected: Vec<u8> = vec![
1577 InstructionCode::MAP_START.into(),
1578 InstructionCode::KEY_VALUE_DYNAMIC.into(),
1579 InstructionCode::TEXT.into(),
1580 ];
1581 expected.extend((long_key.len() as u32).to_le_bytes());
1582 expected.extend(long_key.as_bytes());
1583 expected.extend(vec![
1584 InstructionCode::INT_8.into(),
1585 42,
1586 InstructionCode::SCOPE_END.into(),
1587 ]);
1588 assert_eq!(result, expected);
1589 }
1590
1591 #[test]
1593 fn map_with_dynamic_key() {
1594 init_logger_debug();
1595 let datex_script = "{(1 + 2): 42}";
1596 let result = compile_and_log(datex_script);
1597 let expected = [
1598 InstructionCode::MAP_START.into(),
1599 InstructionCode::KEY_VALUE_DYNAMIC.into(),
1600 InstructionCode::ADD.into(),
1601 InstructionCode::INT_8.into(),
1602 1,
1603 InstructionCode::INT_8.into(),
1604 2,
1605 InstructionCode::INT_8.into(),
1606 42,
1607 InstructionCode::SCOPE_END.into(),
1608 ];
1609 assert_eq!(result, expected);
1610 }
1611
1612 #[test]
1614 fn map_with_multiple_keys() {
1615 init_logger_debug();
1616 let datex_script = "{key: 42, (4): 43, (1 + 2): 44}";
1617 let result = compile_and_log(datex_script);
1618 let expected = vec![
1619 InstructionCode::MAP_START.into(),
1620 InstructionCode::KEY_VALUE_SHORT_TEXT.into(),
1621 3, b'k',
1623 b'e',
1624 b'y',
1625 InstructionCode::INT_8.into(),
1626 42,
1627 InstructionCode::KEY_VALUE_DYNAMIC.into(),
1628 InstructionCode::INT_8.into(),
1629 4,
1630 InstructionCode::INT_8.into(),
1631 43,
1632 InstructionCode::KEY_VALUE_DYNAMIC.into(),
1633 InstructionCode::ADD.into(),
1634 InstructionCode::INT_8.into(),
1635 1,
1636 InstructionCode::INT_8.into(),
1637 2,
1638 InstructionCode::INT_8.into(),
1639 44,
1640 InstructionCode::SCOPE_END.into(),
1641 ];
1642 assert_eq!(result, expected);
1643 }
1644
1645 #[test]
1647 fn empty_map() {
1648 init_logger_debug();
1649 let datex_script = "{}";
1650 let result = compile_and_log(datex_script);
1651 let expected: Vec<u8> = vec![
1652 InstructionCode::MAP_START.into(),
1653 InstructionCode::SCOPE_END.into(),
1654 ];
1655 assert_eq!(result, expected);
1656 }
1657
1658 #[test]
1659 fn allocate_slot() {
1660 init_logger_debug();
1661 let script = "const a = 42";
1662 let result = compile_and_log(script);
1663 assert_eq!(
1664 result,
1665 vec![
1666 InstructionCode::ALLOCATE_SLOT.into(),
1667 0,
1669 0,
1670 0,
1671 0,
1672 InstructionCode::INT_8.into(),
1673 42,
1674 InstructionCode::SCOPE_END.into(),
1675 ]
1676 );
1677 }
1678
1679 #[test]
1680 fn allocate_slot_with_value() {
1681 init_logger_debug();
1682 let script = "const a = 42; a + 1";
1683 let result = compile_and_log(script);
1684 assert_eq!(
1685 result,
1686 vec![
1687 InstructionCode::ALLOCATE_SLOT.into(),
1688 0,
1690 0,
1691 0,
1692 0,
1693 InstructionCode::INT_8.into(),
1694 42,
1695 InstructionCode::SCOPE_END.into(),
1696 InstructionCode::CLOSE_AND_STORE.into(),
1697 InstructionCode::ADD.into(),
1698 InstructionCode::GET_SLOT.into(),
1699 0,
1701 0,
1702 0,
1703 0,
1704 InstructionCode::INT_8.into(),
1705 1,
1706 ]
1707 );
1708 }
1709
1710 #[test]
1711 fn allocate_scoped_slots() {
1712 init_logger_debug();
1713 let script = "const a = 42; (const a = 43; a); a";
1714 let result = compile_and_log(script);
1715 assert_eq!(
1716 result,
1717 vec![
1718 InstructionCode::ALLOCATE_SLOT.into(),
1719 0,
1720 0,
1721 0,
1722 0,
1723 InstructionCode::INT_8.into(),
1724 42,
1725 InstructionCode::SCOPE_END.into(),
1726 InstructionCode::CLOSE_AND_STORE.into(),
1727 InstructionCode::SCOPE_START.into(),
1728 InstructionCode::ALLOCATE_SLOT.into(),
1729 1,
1730 0,
1731 0,
1732 0,
1733 InstructionCode::INT_8.into(),
1734 43,
1735 InstructionCode::SCOPE_END.into(),
1736 InstructionCode::CLOSE_AND_STORE.into(),
1737 InstructionCode::GET_SLOT.into(),
1738 1,
1739 0,
1740 0,
1741 0,
1742 InstructionCode::DROP_SLOT.into(),
1743 1,
1744 0,
1745 0,
1746 0,
1747 InstructionCode::SCOPE_END.into(),
1748 InstructionCode::CLOSE_AND_STORE.into(),
1749 InstructionCode::GET_SLOT.into(),
1750 0,
1752 0,
1753 0,
1754 0,
1755 ]
1756 );
1757 }
1758
1759 #[test]
1760 fn allocate_scoped_slots_with_parent_variables() {
1761 init_logger_debug();
1762 let script = "const a = 42; const b = 41; (const a = 43; a; b); a";
1763 let result = compile_and_log(script);
1764 assert_eq!(
1765 result,
1766 vec![
1767 InstructionCode::ALLOCATE_SLOT.into(),
1768 0,
1769 0,
1770 0,
1771 0,
1772 InstructionCode::INT_8.into(),
1773 42,
1774 InstructionCode::SCOPE_END.into(),
1775 InstructionCode::CLOSE_AND_STORE.into(),
1776 InstructionCode::ALLOCATE_SLOT.into(),
1777 1,
1778 0,
1779 0,
1780 0,
1781 InstructionCode::INT_8.into(),
1782 41,
1783 InstructionCode::SCOPE_END.into(),
1784 InstructionCode::CLOSE_AND_STORE.into(),
1785 InstructionCode::SCOPE_START.into(),
1786 InstructionCode::ALLOCATE_SLOT.into(),
1787 2,
1788 0,
1789 0,
1790 0,
1791 InstructionCode::INT_8.into(),
1792 43,
1793 InstructionCode::SCOPE_END.into(),
1794 InstructionCode::CLOSE_AND_STORE.into(),
1795 InstructionCode::GET_SLOT.into(),
1796 2,
1797 0,
1798 0,
1799 0,
1800 InstructionCode::CLOSE_AND_STORE.into(),
1801 InstructionCode::GET_SLOT.into(),
1802 1,
1803 0,
1804 0,
1805 0,
1806 InstructionCode::DROP_SLOT.into(),
1807 2,
1808 0,
1809 0,
1810 0,
1811 InstructionCode::SCOPE_END.into(),
1812 InstructionCode::CLOSE_AND_STORE.into(),
1813 InstructionCode::GET_SLOT.into(),
1814 0,
1816 0,
1817 0,
1818 0,
1819 ]
1820 );
1821 }
1822
1823 #[test]
1824 fn allocate_ref() {
1825 init_logger_debug();
1826 let script = "const a = &mut 42";
1827 let result = compile_and_log(script);
1828 assert_eq!(
1829 result,
1830 vec![
1831 InstructionCode::ALLOCATE_SLOT.into(),
1832 0,
1834 0,
1835 0,
1836 0,
1837 InstructionCode::CREATE_REF_MUT.into(),
1838 InstructionCode::INT_8.into(),
1839 42,
1840 InstructionCode::SCOPE_END.into(),
1841 ]
1842 );
1843 }
1844
1845 #[test]
1846 fn read_ref() {
1847 init_logger_debug();
1848 let script = "const a = &mut 42; a";
1849 let result = compile_and_log(script);
1850 assert_eq!(
1851 result,
1852 vec![
1853 InstructionCode::ALLOCATE_SLOT.into(),
1854 0,
1856 0,
1857 0,
1858 0,
1859 InstructionCode::CREATE_REF_MUT.into(),
1860 InstructionCode::INT_8.into(),
1861 42,
1862 InstructionCode::SCOPE_END.into(),
1863 InstructionCode::CLOSE_AND_STORE.into(),
1864 InstructionCode::GET_SLOT.into(),
1865 0,
1867 0,
1868 0,
1869 0,
1870 ]
1871 );
1872 }
1873
1874 #[test]
1875 fn compile() {
1876 init_logger_debug();
1877 let result = compile_template(
1878 "? + ?",
1879 &[Integer::from(1).into(), Integer::from(2).into()],
1880 CompileOptions::default(),
1881 );
1882 assert_eq!(
1883 result.unwrap().0,
1884 vec![
1885 InstructionCode::ADD.into(),
1886 InstructionCode::INT_8.into(),
1887 1,
1888 InstructionCode::INT_8.into(),
1889 2
1890 ]
1891 );
1892 }
1893
1894 #[test]
1895 fn compile_macro() {
1896 init_logger_debug();
1897 let a = Integer::from(1);
1898 let result = compile!("?", a);
1899 assert_eq!(result.unwrap().0, vec![InstructionCode::INT_8.into(), 1,]);
1900 }
1901
1902 #[test]
1903 fn compile_macro_multi() {
1904 init_logger_debug();
1905 let result = compile!("? + ?", Integer::from(1), Integer::from(2));
1906 assert_eq!(
1907 result.unwrap().0,
1908 vec![
1909 InstructionCode::ADD.into(),
1910 InstructionCode::INT_8.into(),
1911 1,
1912 InstructionCode::INT_8.into(),
1913 2
1914 ]
1915 );
1916 }
1917
1918 fn get_json_test_string(file_path: &str) -> String {
1919 let file_path = format!("benches/json/{file_path}");
1921 let file_path = std::path::Path::new(&file_path);
1922 let file =
1923 std::fs::File::open(file_path).expect("Failed to open test.json");
1924 let mut reader = std::io::BufReader::new(file);
1925 let mut json_string = String::new();
1926 reader
1927 .read_to_string(&mut json_string)
1928 .expect("Failed to read test.json");
1929 json_string
1930 }
1931
1932 #[test]
1933 fn json_to_dxb_large_file() {
1934 let json = get_json_test_string("test2.json");
1935 let _ = compile_script(&json, CompileOptions::default())
1936 .expect("Failed to parse JSON string");
1937 }
1938
1939 #[test]
1940 fn static_value_detection() {
1941 init_logger_debug();
1942
1943 let script = "1 + 2";
1945 let compilation_scope = get_compilation_scope(script);
1946 assert!(*compilation_scope.has_non_static_value.borrow());
1947
1948 let script = "1 2";
1949 let compilation_scope = get_compilation_scope(script);
1950 assert!(*compilation_scope.has_non_static_value.borrow());
1951
1952 let script = "1;2";
1953 let compilation_scope = get_compilation_scope(script);
1954 assert!(*compilation_scope.has_non_static_value.borrow());
1955
1956 let script = r#"{("x" + "y"): 1}"#;
1957 let compilation_scope = get_compilation_scope(script);
1958 assert!(*compilation_scope.has_non_static_value.borrow());
1959
1960 let script = "1";
1962 let compilation_scope = get_compilation_scope(script);
1963 assert!(!*compilation_scope.has_non_static_value.borrow());
1964
1965 let script = "[]";
1966 let compilation_scope = get_compilation_scope(script);
1967 assert!(!*compilation_scope.has_non_static_value.borrow());
1968
1969 let script = "{}";
1970 let compilation_scope = get_compilation_scope(script);
1971 assert!(!*compilation_scope.has_non_static_value.borrow());
1972
1973 let script = "[1,2,3]";
1974 let compilation_scope = get_compilation_scope(script);
1975 assert!(!*compilation_scope.has_non_static_value.borrow());
1976
1977 let script = "{a: 2}";
1978 let compilation_scope = get_compilation_scope(script);
1979 assert!(!*compilation_scope.has_non_static_value.borrow());
1980
1981 let script = "-42";
1983 let compilation_scope = get_compilation_scope(script);
1984 assert!(!*compilation_scope.has_non_static_value.borrow());
1985 }
1986
1987 #[test]
1988 fn compile_auto_static_value_detection() {
1989 let script = "1";
1990 let (res, _) = compile_script_or_return_static_value(
1991 script,
1992 CompileOptions::default(),
1993 )
1994 .unwrap();
1995 assert_eq!(
1996 res,
1997 StaticValueOrDXB::StaticValue(Some(Integer::from(1).into()))
1998 );
1999
2000 let script = "1 + 2";
2001 let (res, _) = compile_script_or_return_static_value(
2002 script,
2003 CompileOptions::default(),
2004 )
2005 .unwrap();
2006 assert_eq!(
2007 res,
2008 StaticValueOrDXB::Dxb(vec![
2009 InstructionCode::ADD.into(),
2010 InstructionCode::INT_8.into(),
2011 1,
2012 InstructionCode::INT_8.into(),
2013 2,
2014 ])
2015 );
2016 }
2017
2018 #[test]
2019 fn remote_execution() {
2020 let script = "42 :: 43";
2021 let (res, _) =
2022 compile_script(script, CompileOptions::default()).unwrap();
2023 assert_eq!(
2024 res,
2025 vec![
2026 InstructionCode::REMOTE_EXECUTION.into(),
2027 InstructionCode::INT_8.into(),
2029 42,
2030 InstructionCode::EXECUTION_BLOCK.into(),
2032 2,
2034 0,
2035 0,
2036 0,
2037 0,
2039 0,
2040 0,
2041 0,
2042 InstructionCode::INT_8.into(),
2044 43,
2045 ]
2046 );
2047 }
2048
2049 #[test]
2050 fn remote_execution_expression() {
2051 let script = "42 :: 1 + 2";
2052 let (res, _) =
2053 compile_script(script, CompileOptions::default()).unwrap();
2054 assert_eq!(
2055 res,
2056 vec![
2057 InstructionCode::REMOTE_EXECUTION.into(),
2058 InstructionCode::INT_8.into(),
2060 42,
2061 InstructionCode::EXECUTION_BLOCK.into(),
2063 5,
2065 0,
2066 0,
2067 0,
2068 0,
2070 0,
2071 0,
2072 0,
2073 InstructionCode::ADD.into(),
2075 InstructionCode::INT_8.into(),
2076 1,
2077 InstructionCode::INT_8.into(),
2078 2,
2079 ]
2080 );
2081 }
2082
2083 #[test]
2084 fn remote_execution_injected_const() {
2085 init_logger_debug();
2086 let script = "const x = 42; 1 :: x";
2087 let (res, _) =
2088 compile_script(script, CompileOptions::default()).unwrap();
2089 assert_eq!(
2090 res,
2091 vec![
2092 InstructionCode::ALLOCATE_SLOT.into(),
2093 0,
2095 0,
2096 0,
2097 0,
2098 InstructionCode::INT_8.into(),
2099 42,
2100 InstructionCode::SCOPE_END.into(),
2101 InstructionCode::CLOSE_AND_STORE.into(),
2102 InstructionCode::REMOTE_EXECUTION.into(),
2103 InstructionCode::INT_8.into(),
2105 1,
2106 InstructionCode::EXECUTION_BLOCK.into(),
2108 5,
2110 0,
2111 0,
2112 0,
2113 1,
2115 0,
2116 0,
2117 0,
2118 0,
2120 0,
2121 0,
2122 0,
2123 InstructionCode::GET_SLOT.into(),
2125 0,
2127 0,
2128 0,
2129 0,
2130 ]
2131 );
2132 }
2133
2134 #[test]
2135 fn remote_execution_injected_var() {
2136 init_logger_debug();
2137 let script = "var x = 42; 1 :: x; x = 43;";
2140 let (res, _) =
2141 compile_script(script, CompileOptions::default()).unwrap();
2142 assert_eq!(
2143 res,
2144 vec![
2145 InstructionCode::ALLOCATE_SLOT.into(),
2146 0,
2148 0,
2149 0,
2150 0,
2151 InstructionCode::INT_8.into(),
2152 42,
2153 InstructionCode::SCOPE_END.into(),
2154 InstructionCode::ALLOCATE_SLOT.into(),
2155 1,
2157 0,
2158 0,
2159 0,
2160 InstructionCode::CREATE_REF.into(),
2162 InstructionCode::GET_SLOT.into(),
2164 0,
2166 0,
2167 0,
2168 0,
2169 InstructionCode::SCOPE_END.into(),
2170 InstructionCode::CLOSE_AND_STORE.into(),
2171 InstructionCode::REMOTE_EXECUTION.into(),
2172 InstructionCode::INT_8.into(),
2174 1,
2175 InstructionCode::EXECUTION_BLOCK.into(),
2177 5,
2179 0,
2180 0,
2181 0,
2182 1,
2184 0,
2185 0,
2186 0,
2187 0,
2189 0,
2190 0,
2191 0,
2192 InstructionCode::GET_SLOT.into(),
2194 0,
2196 0,
2197 0,
2198 0,
2199 InstructionCode::CLOSE_AND_STORE.into(),
2200 InstructionCode::SET_SLOT.into(),
2203 0,
2205 0,
2206 0,
2207 0,
2208 InstructionCode::INT_8.into(),
2209 43,
2210 InstructionCode::SCOPE_END.into(),
2211 InstructionCode::CLOSE_AND_STORE.into(),
2212 ]
2213 );
2214 }
2215
2216 #[test]
2217 fn remote_execution_injected_consts() {
2218 let script = "const x = 42; const y = 69; 1 :: x + y";
2219 let (res, _) =
2220 compile_script(script, CompileOptions::default()).unwrap();
2221 assert_eq!(
2222 res,
2223 vec![
2224 InstructionCode::ALLOCATE_SLOT.into(),
2225 0,
2227 0,
2228 0,
2229 0,
2230 InstructionCode::INT_8.into(),
2231 42,
2232 InstructionCode::SCOPE_END.into(),
2233 InstructionCode::CLOSE_AND_STORE.into(),
2234 InstructionCode::ALLOCATE_SLOT.into(),
2235 1,
2237 0,
2238 0,
2239 0,
2240 InstructionCode::INT_8.into(),
2241 69,
2242 InstructionCode::SCOPE_END.into(),
2243 InstructionCode::CLOSE_AND_STORE.into(),
2244 InstructionCode::REMOTE_EXECUTION.into(),
2245 InstructionCode::INT_8.into(),
2247 1,
2248 InstructionCode::EXECUTION_BLOCK.into(),
2250 11,
2252 0,
2253 0,
2254 0,
2255 2,
2257 0,
2258 0,
2259 0,
2260 0,
2262 0,
2263 0,
2264 0,
2265 1,
2267 0,
2268 0,
2269 0,
2270 InstructionCode::ADD.into(),
2272 InstructionCode::GET_SLOT.into(),
2273 0,
2275 0,
2276 0,
2277 0,
2278 InstructionCode::GET_SLOT.into(),
2279 1,
2281 0,
2282 0,
2283 0,
2284 ]
2285 );
2286 }
2287
2288 #[test]
2289 fn remote_execution_shadow_const() {
2290 let script = "const x = 42; const y = 69; 1 :: (const x = 5; x + y)";
2291 let (res, _) =
2292 compile_script(script, CompileOptions::default()).unwrap();
2293 assert_eq!(
2294 res,
2295 vec![
2296 InstructionCode::ALLOCATE_SLOT.into(),
2297 0,
2299 0,
2300 0,
2301 0,
2302 InstructionCode::INT_8.into(),
2303 42,
2304 InstructionCode::SCOPE_END.into(),
2305 InstructionCode::CLOSE_AND_STORE.into(),
2306 InstructionCode::ALLOCATE_SLOT.into(),
2307 1,
2309 0,
2310 0,
2311 0,
2312 InstructionCode::INT_8.into(),
2313 69,
2314 InstructionCode::SCOPE_END.into(),
2315 InstructionCode::CLOSE_AND_STORE.into(),
2316 InstructionCode::REMOTE_EXECUTION.into(),
2317 InstructionCode::INT_8.into(),
2319 1,
2320 InstructionCode::EXECUTION_BLOCK.into(),
2322 20,
2324 0,
2325 0,
2326 0,
2327 1,
2329 0,
2330 0,
2331 0,
2332 1,
2334 0,
2335 0,
2336 0,
2337 InstructionCode::ALLOCATE_SLOT.into(),
2339 1,
2341 0,
2342 0,
2343 0,
2344 InstructionCode::INT_8.into(),
2345 5,
2346 InstructionCode::SCOPE_END.into(),
2347 InstructionCode::CLOSE_AND_STORE.into(),
2348 InstructionCode::ADD.into(),
2350 InstructionCode::GET_SLOT.into(),
2351 1,
2353 0,
2354 0,
2355 0,
2356 InstructionCode::GET_SLOT.into(),
2357 0,
2359 0,
2360 0,
2361 0,
2362 ]
2363 );
2364 }
2365
2366 #[test]
2367 fn remote_execution_nested() {
2368 let script = "const x = 42; (1 :: (2 :: x))";
2369 let (res, _) =
2370 compile_script(script, CompileOptions::default()).unwrap();
2371
2372 assert_eq!(
2373 res,
2374 vec![
2375 InstructionCode::ALLOCATE_SLOT.into(),
2376 0,
2378 0,
2379 0,
2380 0,
2381 InstructionCode::INT_8.into(),
2382 42,
2383 InstructionCode::SCOPE_END.into(),
2384 InstructionCode::CLOSE_AND_STORE.into(),
2385 InstructionCode::REMOTE_EXECUTION.into(),
2386 InstructionCode::INT_8.into(),
2388 1,
2389 InstructionCode::EXECUTION_BLOCK.into(),
2391 21,
2393 0,
2394 0,
2395 0,
2396 1,
2398 0,
2399 0,
2400 0,
2401 0,
2403 0,
2404 0,
2405 0,
2406 InstructionCode::REMOTE_EXECUTION.into(),
2408 InstructionCode::INT_8.into(),
2410 2,
2411 InstructionCode::EXECUTION_BLOCK.into(),
2413 5,
2415 0,
2416 0,
2417 0,
2418 1,
2420 0,
2421 0,
2422 0,
2423 0,
2425 0,
2426 0,
2427 0,
2428 InstructionCode::GET_SLOT.into(),
2429 0,
2431 0,
2432 0,
2433 0,
2434 ]
2435 );
2436 }
2437
2438 #[test]
2439 fn remote_execution_nested2() {
2440 let script = "const x = 42; (1 :: (x :: x))";
2441 let (res, _) =
2442 compile_script(script, CompileOptions::default()).unwrap();
2443
2444 assert_eq!(
2445 res,
2446 vec![
2447 InstructionCode::ALLOCATE_SLOT.into(),
2448 0,
2450 0,
2451 0,
2452 0,
2453 InstructionCode::INT_8.into(),
2454 42,
2455 InstructionCode::SCOPE_END.into(),
2456 InstructionCode::CLOSE_AND_STORE.into(),
2457 InstructionCode::REMOTE_EXECUTION.into(),
2458 InstructionCode::INT_8.into(),
2460 1,
2461 InstructionCode::EXECUTION_BLOCK.into(),
2463 24,
2465 0,
2466 0,
2467 0,
2468 1,
2470 0,
2471 0,
2472 0,
2473 0,
2475 0,
2476 0,
2477 0,
2478 InstructionCode::REMOTE_EXECUTION.into(),
2480 InstructionCode::GET_SLOT.into(),
2482 0,
2483 0,
2484 0,
2485 0,
2486 InstructionCode::EXECUTION_BLOCK.into(),
2488 5,
2490 0,
2491 0,
2492 0,
2493 1,
2495 0,
2496 0,
2497 0,
2498 0,
2500 0,
2501 0,
2502 0,
2503 InstructionCode::GET_SLOT.into(),
2504 0,
2506 0,
2507 0,
2508 0,
2509 ]
2510 );
2511 }
2512
2513 #[test]
2514 fn assignment_to_const() {
2515 init_logger_debug();
2516 let script = "const a = 42; a = 43";
2517 let result = compile_script(script, CompileOptions::default());
2518 assert_matches!(result, Err(CompilerError::AssignmentToConst { .. }));
2519 }
2520
2521 #[test]
2522 fn assignment_to_const_mut() {
2523 init_logger_debug();
2524 let script = "const a = &mut 42; a = 43";
2525 let result = compile_script(script, CompileOptions::default());
2526 assert_matches!(result, Err(CompilerError::AssignmentToConst { .. }));
2527 }
2528
2529 #[test]
2530 fn internal_assignment_to_const_mut() {
2531 init_logger_debug();
2532 let script = "const a = &mut 42; *a = 43";
2533 let result = compile_script(script, CompileOptions::default());
2534 assert_matches!(result, Ok(_));
2535 }
2536
2537 #[test]
2538 fn addition_to_const_mut_ref() {
2539 init_logger_debug();
2540 let script = "const a = &mut 42; *a += 1;";
2541 let result = compile_script(script, CompileOptions::default());
2542 assert_matches!(result, Ok(_));
2543 }
2544
2545 #[test]
2546 fn addition_to_const_variable() {
2547 init_logger_debug();
2548 let script = "const a = 42; a += 1";
2549 let result = compile_script(script, CompileOptions::default());
2550 assert_matches!(result, Err(CompilerError::AssignmentToConst { .. }));
2551 }
2552
2553 #[ignore = "implement type inference (precompiler)"]
2554 #[test]
2555 fn mutation_of_immutable_value() {
2556 init_logger_debug();
2557 let script = "const a = {x: 10}; a.x = 20;";
2558 let result = compile_script(script, CompileOptions::default());
2559 assert_matches!(
2560 result,
2561 Err(CompilerError::AssignmentToImmutableValue { .. })
2562 );
2563 }
2564
2565 #[ignore = "implement type inference (precompiler)"]
2566 #[test]
2567 fn mutation_of_mutable_value() {
2568 init_logger_debug();
2569 let script = "const a = mut {x: 10}; a.x = 20;";
2570 let result = compile_script(script, CompileOptions::default());
2571 assert_matches!(
2572 result,
2573 Err(CompilerError::AssignmentToImmutableValue { .. })
2574 );
2575 }
2576
2577 #[ignore = "implement type inference (precompiler)"]
2590 #[test]
2591 fn addition_to_immutable_ref() {
2592 init_logger_debug();
2593 let script = "const a = &42; *a += 1;";
2594 let result = compile_script(script, CompileOptions::default());
2595 assert_matches!(
2596 result,
2597 Err(CompilerError::AssignmentToImmutableReference { .. })
2598 );
2599 }
2600
2601 #[test]
2602 fn slot_endpoint() {
2603 let script = "#endpoint";
2604 let (res, _) =
2605 compile_script(script, CompileOptions::default()).unwrap();
2606 assert_eq!(
2607 res,
2608 vec![
2609 InstructionCode::GET_SLOT.into(),
2610 0,
2612 0xff,
2613 0xff,
2614 0xff
2615 ]
2616 );
2617 }
2618
2619 #[test]
2621 fn deref() {
2622 let script = "*10";
2623 let (res, _) =
2624 compile_script(script, CompileOptions::default()).unwrap();
2625 assert_eq!(
2626 res,
2627 vec![
2628 InstructionCode::DEREF.into(),
2629 InstructionCode::INT_8.into(),
2630 10,
2632 InstructionCode::SCOPE_END.into(),
2633 ]
2634 );
2635 }
2636
2637 #[test]
2638 fn type_literal_integer() {
2639 let script = "type(1)";
2640 let (res, _) =
2641 compile_script(script, CompileOptions::default()).unwrap();
2642 assert_eq!(
2643 res,
2644 vec![
2645 InstructionCode::TYPE_EXPRESSION.into(),
2646 TypeSpaceInstructionCode::TYPE_LITERAL_INTEGER.into(),
2647 2,
2649 1,
2650 0,
2651 0,
2652 0,
2653 1
2654 ]
2655 );
2656 }
2657
2658 #[test]
2659 fn type_core_type_integer() {
2660 let script = "integer";
2661 let (res, _) =
2662 compile_script(script, CompileOptions::default()).unwrap();
2663 let mut instructions: Vec<u8> =
2664 vec![InstructionCode::GET_INTERNAL_REF.into()];
2665 instructions.append(
2667 &mut PointerAddress::from(CoreLibPointerId::Integer(None))
2668 .bytes()
2669 .to_vec(),
2670 );
2671 assert_eq!(res, instructions);
2672 }
2673}