1use crate::compiler::error::{
2 CompilerError, DetailedCompilerErrors, SimpleOrDetailedCompilerError,
3 SpannedCompilerError,
4};
5use crate::global::dxb_block::DXBBlock;
6use crate::global::operators::assignment::AssignmentOperator;
7use crate::global::protocol_structures::block_header::BlockHeader;
8use crate::global::protocol_structures::encrypted_header::EncryptedHeader;
9use crate::global::protocol_structures::routing_header::RoutingHeader;
10use core::cell::RefCell;
11
12use crate::ast::expressions::{
13 BinaryOperation, ComparisonOperation, DatexExpression, DatexExpressionData,
14 DerefAssignment, RemoteExecution, Slot, Statements, UnaryOperation,
15 UnboundedStatement, VariableAccess, VariableAssignment,
16 VariableDeclaration, VariableKind,
17};
18use crate::compiler::context::{CompilationContext, VirtualSlot};
19use crate::compiler::error::{
20 DetailedCompilerErrorsWithMaybeRichAst,
21 SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst,
22};
23use crate::compiler::metadata::CompileMetadata;
24use crate::compiler::scope::CompilationScope;
25use crate::compiler::type_compiler::compile_type_expression;
26use crate::global::instruction_codes::InstructionCode;
27use crate::global::slots::InternalSlot;
28use crate::libs::core::CoreLibPointerId;
29use crate::parser::parser_result::ValidDatexParseResult;
30
31use crate::ast::resolved_variable::VariableId;
32use crate::core_compiler::value_compiler::{
33 append_boolean, append_decimal, append_encoded_integer, append_endpoint,
34 append_float_as_i16, append_float_as_i32, append_instruction_code,
35 append_integer, append_text, append_typed_decimal, append_typed_integer,
36 append_value_container,
37};
38use crate::core_compiler::value_compiler::{append_get_ref, append_key_string};
39use crate::parser::{Parser, ParserOptions};
40use crate::references::reference::ReferenceMutability;
41use crate::runtime::execution::context::ExecutionMode;
42use crate::stdlib::rc::Rc;
43use crate::stdlib::vec::Vec;
44use crate::time::Instant;
45use crate::utils::buffers::append_u32;
46use crate::utils::buffers::{append_u8, append_u16};
47use crate::values::core_values::decimal::Decimal;
48use crate::values::pointer::PointerAddress;
49use crate::values::value_container::ValueContainer;
50use log::{debug, info};
51use precompiler::options::PrecompilerOptions;
52use precompiler::precompile_ast;
53use precompiler::precompiled_ast::{AstMetadata, RichAst, VariableMetadata};
54
55pub mod context;
56pub mod error;
57pub mod metadata;
58pub mod scope;
59pub mod type_compiler;
60
61pub mod precompiler;
62#[cfg(feature = "std")]
63pub mod workspace;
64
65#[derive(Clone, Default)]
66pub struct CompileOptions {
67 pub compile_scope: CompilationScope,
68 pub parser_options: ParserOptions,
69}
70
71impl CompileOptions {
72 pub fn new_with_scope(compile_scope: CompilationScope) -> Self {
73 CompileOptions {
74 compile_scope,
75 parser_options: ParserOptions::default(),
76 }
77 }
78}
79
80#[derive(Debug, Clone)]
81pub enum StaticValueOrDXB {
82 StaticValue(Option<ValueContainer>),
83 DXB(Vec<u8>),
84}
85
86impl From<Vec<u8>> for StaticValueOrDXB {
87 fn from(dxb: Vec<u8>) -> Self {
88 StaticValueOrDXB::DXB(dxb)
89 }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, Copy)]
93pub enum VariableModel {
94 Constant,
97 VariableSlot,
100 VariableReference,
104}
105
106impl From<VariableRepresentation> for VariableModel {
107 fn from(value: VariableRepresentation) -> Self {
108 match value {
109 VariableRepresentation::Constant(_) => VariableModel::Constant,
110 VariableRepresentation::VariableSlot(_) => {
111 VariableModel::VariableSlot
112 }
113 VariableRepresentation::VariableReference { .. } => {
114 VariableModel::VariableReference
115 }
116 }
117 }
118}
119
120impl VariableModel {
121 pub fn infer(
123 variable_kind: VariableKind,
124 variable_metadata: Option<VariableMetadata>,
125 execution_mode: ExecutionMode,
126 ) -> Self {
127 if variable_kind == VariableKind::Const {
129 VariableModel::Constant
130 }
131 else if variable_metadata.is_none()
136 || variable_metadata.unwrap().is_cross_realm
137 || execution_mode.is_unbounded()
138 {
139 VariableModel::VariableReference
140 }
141 else {
143 VariableModel::VariableSlot
144 }
145 }
146
147 pub fn infer_from_ast_metadata_and_type(
148 ast_metadata: &AstMetadata,
149 variable_id: Option<VariableId>,
150 variable_kind: VariableKind,
151 execution_mode: ExecutionMode,
152 ) -> Self {
153 let variable_metadata =
154 variable_id.and_then(|id| ast_metadata.variable_metadata(id));
155 Self::infer(variable_kind, variable_metadata.cloned(), execution_mode)
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, Copy)]
160pub enum VariableRepresentation {
161 Constant(VirtualSlot),
162 VariableSlot(VirtualSlot),
163 VariableReference {
164 variable_slot: VirtualSlot,
166 container_slot: VirtualSlot,
168 },
169}
170
171#[derive(Debug, Clone)]
173pub struct Variable {
174 pub name: String,
175 pub kind: VariableKind,
176 pub representation: VariableRepresentation,
177}
178
179impl Variable {
180 pub fn new_const(name: String, slot: VirtualSlot) -> Self {
181 Variable {
182 name,
183 kind: VariableKind::Const,
184 representation: VariableRepresentation::Constant(slot),
185 }
186 }
187
188 pub fn new_variable_slot(
189 name: String,
190 kind: VariableKind,
191 slot: VirtualSlot,
192 ) -> Self {
193 Variable {
194 name,
195 kind,
196 representation: VariableRepresentation::VariableSlot(slot),
197 }
198 }
199
200 pub fn new_variable_reference(
201 name: String,
202 kind: VariableKind,
203 variable_slot: VirtualSlot,
204 container_slot: VirtualSlot,
205 ) -> Self {
206 Variable {
207 name,
208 kind,
209 representation: VariableRepresentation::VariableReference {
210 variable_slot,
211 container_slot,
212 },
213 }
214 }
215
216 pub fn slots(&self) -> Vec<VirtualSlot> {
217 match &self.representation {
218 VariableRepresentation::Constant(slot) => vec![*slot],
219 VariableRepresentation::VariableSlot(slot) => vec![*slot],
220 VariableRepresentation::VariableReference {
221 variable_slot,
222 container_slot,
223 } => {
224 vec![*variable_slot, *container_slot]
225 }
226 }
227 }
228}
229
230pub fn compile_block(
233 datex_script: &str,
234) -> Result<Vec<u8>, SimpleOrDetailedCompilerError> {
235 let (body, _) = compile_script(datex_script, CompileOptions::default())?;
236
237 let routing_header = RoutingHeader::default();
238
239 let block_header = BlockHeader::default();
240 let encrypted_header = EncryptedHeader::default();
241
242 let block =
243 DXBBlock::new(routing_header, block_header, encrypted_header, body);
244
245 let bytes = block
246 .to_bytes()
247 .map_err(|e| CompilerError::SerializationError)?;
248 Ok(bytes)
249}
250
251pub fn compile_script(
253 datex_script: &str,
254 options: CompileOptions,
255) -> Result<(Vec<u8>, CompilationScope), SpannedCompilerError> {
256 compile_template(datex_script, &[], options)
257}
258
259pub fn extract_static_value_from_script(
263 datex_script: &str,
264) -> Result<Option<ValueContainer>, SpannedCompilerError> {
265 let valid_parse_result = Parser::parse_with_default_options(datex_script)?;
266 extract_static_value_from_ast(&valid_parse_result)
267 .map(Some)
268 .map_err(SpannedCompilerError::from)
269}
270
271pub fn compile_script_or_return_static_value<'a>(
275 datex_script: &'a str,
276 mut options: CompileOptions,
277) -> Result<(StaticValueOrDXB, CompilationScope), SpannedCompilerError> {
278 let ast = parse_datex_script_to_rich_ast_simple_error(
279 datex_script,
280 &mut options,
281 )?;
282 let mut compilation_context = CompilationContext::new(
283 Vec::with_capacity(256),
284 vec![],
285 options.compile_scope.execution_mode,
286 );
287 let scope = compile_ast(ast.clone(), &mut compilation_context, options)?;
289 if compilation_context.has_non_static_value {
290 Ok((StaticValueOrDXB::DXB(compilation_context.buffer), scope))
291 } else {
292 extract_static_value_from_ast(&ast.ast)
294 .map(|value| (StaticValueOrDXB::StaticValue(Some(value)), scope))
295 .map_err(SpannedCompilerError::from)
296 }
297}
298
299fn ensure_statements(
302 ast: &mut DatexExpression,
303 unbounded_section: Option<UnboundedStatement>,
304) -> bool {
305 if let DatexExpressionData::Statements(Statements {
306 is_terminated,
307 unbounded,
308 ..
309 }) = &mut ast.data
310 {
311 *unbounded = unbounded_section;
312 *is_terminated
313 } else {
314 let original_ast = ast.clone();
316 ast.data = DatexExpressionData::Statements(Statements {
317 statements: vec![original_ast],
318 is_terminated: false,
319 unbounded: unbounded_section,
320 });
321 false
322 }
323}
324
325pub fn parse_datex_script_to_rich_ast_simple_error(
328 datex_script: &str,
329 options: &mut CompileOptions,
330) -> Result<RichAst, SpannedCompilerError> {
331 let parse_start = Instant::now();
342 let mut valid_parse_result =
343 Parser::parse(datex_script, options.parser_options.clone())?;
344
345 let is_terminated = if let ExecutionMode::Unbounded { has_next } =
347 options.compile_scope.execution_mode
348 {
349 ensure_statements(
350 &mut valid_parse_result,
351 Some(UnboundedStatement {
352 is_first: !options.compile_scope.was_used,
353 is_last: !has_next,
354 }),
355 )
356 } else {
357 matches!(
358 valid_parse_result.data,
359 DatexExpressionData::Statements(Statements {
360 is_terminated: true,
361 ..
362 })
363 )
364 };
365 debug!(" [parse took {} ms]", parse_start.elapsed().as_millis());
366 let precompile_start = Instant::now();
367 let res = precompile_to_rich_ast(
368 valid_parse_result,
369 &mut options.compile_scope,
370 PrecompilerOptions {
371 detailed_errors: false,
372 },
373 )
374 .map_err(|e| match e {
375 SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst::Simple(e) => e,
376 _ => unreachable!(), })
378 .inspect(|ast| {
379 ast.metadata.borrow_mut().is_terminated = is_terminated;
381 });
382 debug!(
383 " [precompile took {} ms]",
384 precompile_start.elapsed().as_millis()
385 );
386 res
387}
388
389pub fn parse_datex_script_to_rich_ast_detailed_errors(
392 datex_script: &str,
393 options: &mut CompileOptions,
394) -> Result<RichAst, DetailedCompilerErrorsWithMaybeRichAst> {
395 let (ast, parser_errors) =
396 Parser::parse_collecting_with_default_options(datex_script)
397 .into_ast_and_errors();
398 precompile_to_rich_ast(
399 ast,
400 &mut options.compile_scope,
401 PrecompilerOptions {
402 detailed_errors: true,
403 },
404 )
405 .map_err(|e| match e {
406 SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst::Detailed(
407 mut e,
408 ) => {
409 e.errors.errors.extend(
411 parser_errors.into_iter().map(SpannedCompilerError::from),
412 );
413 e.into()
414 }
415 _ => unreachable!(), })
417}
418
419pub fn compile_template(
421 datex_script: &str,
422 inserted_values: &[ValueContainer],
423 mut options: CompileOptions,
424) -> Result<(Vec<u8>, CompilationScope), SpannedCompilerError> {
425 let ast = parse_datex_script_to_rich_ast_simple_error(
426 datex_script,
427 &mut options,
428 )?;
429 let mut compilation_context = CompilationContext::new(
430 Vec::with_capacity(256),
431 inserted_values.to_vec(),
433 options.compile_scope.execution_mode,
434 );
435 let compile_start = Instant::now();
436 let res = compile_ast(ast, &mut compilation_context, options)
437 .map(|scope| (compilation_context.buffer, scope))
438 .map_err(SpannedCompilerError::from);
439 debug!(
440 " [compile_ast took {} ms]",
441 compile_start.elapsed().as_millis()
442 );
443 res
444}
445
446fn compile_ast(
448 ast: RichAst,
449 compilation_context: &mut CompilationContext,
450 options: CompileOptions,
451) -> Result<CompilationScope, CompilerError> {
452 let compilation_scope =
453 compile_rich_ast(compilation_context, ast, options.compile_scope)?;
454 Ok(compilation_scope)
455}
456
457fn extract_static_value_from_ast(
461 ast: &DatexExpression,
462) -> Result<ValueContainer, CompilerError> {
463 if let DatexExpressionData::Placeholder = ast.data {
464 return Err(CompilerError::NonStaticValue);
465 }
466 ValueContainer::try_from(&ast.data)
467 .map_err(|_| CompilerError::NonStaticValue)
468}
469
470#[macro_export]
478macro_rules! compile {
479 ($fmt:literal $(, $arg:expr )* $(,)?) => {
480 {
481 let script: &str = $fmt.into();
482 let values: &[$crate::values::value_container::ValueContainer] = &[$($arg.into()),*];
483
484 $crate::compiler::compile_template(&script, values, $crate::compiler::CompileOptions::default())
485 }
486 }
487}
488
489fn precompile_to_rich_ast(
491 valid_parse_result: DatexExpression,
492 scope: &mut CompilationScope,
493 precompiler_options: PrecompilerOptions,
494) -> Result<RichAst, SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst> {
495 if scope.execution_mode == ExecutionMode::Static && scope.was_used {
497 return Err(
498 SimpleCompilerErrorOrDetailedCompilerErrorWithRichAst::Simple(
499 SpannedCompilerError::from(
500 CompilerError::OnceScopeUsedMultipleTimes,
501 ),
502 ),
503 );
504 }
505
506 scope.was_used = true;
508
509 let rich_ast = if let Some(precompiler_data) = &scope.precompiler_data {
510 precompile_ast(
512 valid_parse_result,
513 &mut precompiler_data.precompiler_scope_stack.borrow_mut(),
514 precompiler_data.rich_ast.metadata.clone(),
515 precompiler_options,
516 )?
517 } else {
518 RichAst::new_without_metadata(valid_parse_result)
520 };
521
522 Ok(rich_ast)
523}
524
525pub fn compile_rich_ast(
526 compilation_context: &mut CompilationContext,
527 rich_ast: RichAst,
528 scope: CompilationScope,
529) -> Result<CompilationScope, CompilerError> {
530 let scope = compile_expression(
531 compilation_context,
532 rich_ast,
533 CompileMetadata::outer(),
534 scope,
535 )?;
536
537 compilation_context.remap_virtual_slots();
539 Ok(scope)
540}
541
542fn compile_expression(
543 compilation_context: &mut CompilationContext,
544 rich_ast: RichAst,
545 meta: CompileMetadata,
546 mut scope: CompilationScope,
547) -> Result<CompilationScope, CompilerError> {
548 let metadata = rich_ast.metadata;
549 match rich_ast.ast.data.clone() {
551 DatexExpressionData::Integer(int) => {
552 append_integer(&mut compilation_context.buffer, &int);
553 }
554 DatexExpressionData::TypedInteger(typed_int) => {
555 append_encoded_integer(&mut compilation_context.buffer, &typed_int);
556 }
557 DatexExpressionData::Decimal(decimal) => match &decimal {
558 Decimal::Finite(big_decimal) if big_decimal.is_integer() => {
559 if let Some(int) = big_decimal.to_i16() {
560 append_float_as_i16(&mut compilation_context.buffer, int);
561 } else if let Some(int) = big_decimal.to_i32() {
562 append_float_as_i32(&mut compilation_context.buffer, int);
563 } else {
564 append_decimal(&mut compilation_context.buffer, &decimal);
565 }
566 }
567 _ => {
568 append_decimal(&mut compilation_context.buffer, &decimal);
569 }
570 },
571 DatexExpressionData::TypedDecimal(typed_decimal) => {
572 append_typed_decimal(
573 &mut compilation_context.buffer,
574 &typed_decimal,
575 );
576 }
577 DatexExpressionData::Text(text) => {
578 append_text(&mut compilation_context.buffer, &text);
579 }
580 DatexExpressionData::Boolean(boolean) => {
581 append_boolean(&mut compilation_context.buffer, boolean);
582 }
583 DatexExpressionData::Endpoint(endpoint) => {
584 append_endpoint(&mut compilation_context.buffer, &endpoint);
585 }
586 DatexExpressionData::Null => {
587 append_instruction_code(
588 &mut compilation_context.buffer,
589 InstructionCode::NULL,
590 );
591 }
592 DatexExpressionData::List(list) => {
593 match list.items.len() {
594 0..=255 => {
595 compilation_context
596 .append_instruction_code(InstructionCode::SHORT_LIST);
597 append_u8(
598 &mut compilation_context.buffer,
599 list.items.len() as u8,
600 );
601 }
602 _ => {
603 compilation_context
604 .append_instruction_code(InstructionCode::LIST);
605 append_u32(
606 &mut compilation_context.buffer,
607 list.items.len() as u32, );
609 }
610 }
611 for item in list.items {
612 scope = compile_expression(
613 compilation_context,
614 RichAst::new(item, &metadata),
615 CompileMetadata::default(),
616 scope,
617 )?;
618 }
619 }
620 DatexExpressionData::Map(map) => {
621 match map.entries.len() {
623 0..=255 => {
624 compilation_context
625 .append_instruction_code(InstructionCode::SHORT_MAP);
626 append_u8(
627 &mut compilation_context.buffer,
628 map.entries.len() as u8,
629 );
630 }
631 _ => {
632 compilation_context
633 .append_instruction_code(InstructionCode::MAP);
634 append_u32(
635 &mut compilation_context.buffer,
636 map.entries.len() as u32, );
638 }
639 }
640 for (key, value) in map.entries {
641 scope = compile_key_value_entry(
642 compilation_context,
643 key,
644 value,
645 &metadata,
646 scope,
647 )?;
648 }
649 }
650 DatexExpressionData::Placeholder => {
651 append_value_container(
652 &mut compilation_context.buffer,
653 compilation_context
654 .inserted_values
655 .get(compilation_context.inserted_value_index)
656 .unwrap(),
657 );
658 compilation_context.inserted_value_index += 1;
659 }
660
661 DatexExpressionData::Statements(Statements {
663 mut statements,
664 is_terminated,
665 unbounded,
666 }) => {
667 compilation_context.mark_has_non_static_value();
668 if unbounded.is_none() && statements.len() == 1 && !is_terminated {
671 scope = compile_expression(
672 compilation_context,
673 RichAst::new(statements.remove(0), &metadata),
674 CompileMetadata::default(),
675 scope,
676 )?;
677 } else {
678 let is_outer_context = meta.is_outer_context();
679
680 let mut child_scope = if is_outer_context {
682 scope
683 } else {
684 scope.push()
685 };
686
687 if let Some(UnboundedStatement { is_first, .. }) = unbounded {
688 if is_first {
690 compilation_context.append_instruction_code(
691 InstructionCode::UNBOUNDED_STATEMENTS,
692 );
693 }
694 }
696 else {
698 let len = statements.len();
699
700 match len {
701 0..=255 => {
702 compilation_context.append_instruction_code(
703 InstructionCode::SHORT_STATEMENTS,
704 );
705 append_u8(
706 &mut compilation_context.buffer,
707 len as u8,
708 );
709 }
710 _ => {
711 compilation_context.append_instruction_code(
712 InstructionCode::STATEMENTS,
713 );
714 append_u32(
715 &mut compilation_context.buffer,
716 len as u32, );
718 }
719 }
720
721 append_u8(
723 &mut compilation_context.buffer,
724 if is_terminated { 1 } else { 0 },
725 );
726 }
727
728 for (i, statement) in statements.into_iter().enumerate() {
729 child_scope = compile_expression(
730 compilation_context,
731 RichAst::new(statement, &metadata),
732 CompileMetadata::default(),
733 child_scope,
734 )?;
735 }
736 if !meta.is_outer_context() {
737 let scope_data = child_scope
738 .pop()
739 .ok_or(CompilerError::ScopePopError)?;
740 scope = scope_data.0; for slot_address in scope_data.1 {
743 compilation_context.append_instruction_code(
744 InstructionCode::DROP_SLOT,
745 );
746 compilation_context
748 .insert_virtual_slot_address(slot_address);
749 }
750 } else {
751 scope = child_scope;
752 }
753
754 if let Some(UnboundedStatement { is_last: true, .. }) =
756 unbounded
757 {
758 compilation_context.append_instruction_code(
759 InstructionCode::UNBOUNDED_STATEMENTS_END,
760 );
761 append_u8(
763 &mut compilation_context.buffer,
764 if is_terminated { 1 } else { 0 },
765 );
766 }
767 }
768 }
769
770 DatexExpressionData::UnaryOperation(UnaryOperation {
772 operator,
773 expression,
774 }) => {
775 compilation_context
776 .append_instruction_code(InstructionCode::from(&operator));
777 scope = compile_expression(
778 compilation_context,
779 RichAst::new(*expression, &metadata),
780 CompileMetadata::default(),
781 scope,
782 )?;
783 }
784
785 DatexExpressionData::BinaryOperation(BinaryOperation {
787 operator,
788 left,
789 right,
790 ..
791 }) => {
792 compilation_context.mark_has_non_static_value();
793 compilation_context
795 .append_instruction_code(InstructionCode::from(&operator));
796 scope = compile_expression(
797 compilation_context,
798 RichAst::new(*left, &metadata),
799 CompileMetadata::default(),
800 scope,
801 )?;
802 scope = compile_expression(
803 compilation_context,
804 RichAst::new(*right, &metadata),
805 CompileMetadata::default(),
806 scope,
807 )?;
808 }
809
810 DatexExpressionData::ComparisonOperation(ComparisonOperation {
812 operator,
813 left,
814 right,
815 }) => {
816 compilation_context.mark_has_non_static_value();
817 compilation_context
819 .append_instruction_code(InstructionCode::from(&operator));
820 scope = compile_expression(
821 compilation_context,
822 RichAst::new(*left, &metadata),
823 CompileMetadata::default(),
824 scope,
825 )?;
826 scope = compile_expression(
827 compilation_context,
828 RichAst::new(*right, &metadata),
829 CompileMetadata::default(),
830 scope,
831 )?;
832 }
833
834 DatexExpressionData::Apply(apply) => {
836 compilation_context.mark_has_non_static_value();
837
838 let len = apply.arguments.len();
840 match len {
841 0 => {
842 compilation_context
843 .append_instruction_code(InstructionCode::APPLY_ZERO);
844 }
845 1 => {
846 compilation_context
847 .append_instruction_code(InstructionCode::APPLY_SINGLE);
848 }
849 2..=65_535 => {
851 compilation_context
852 .append_instruction_code(InstructionCode::APPLY);
853 append_u16(
855 &mut compilation_context.buffer,
856 apply.arguments.len() as u16,
857 );
858 }
859 _ => return Err(CompilerError::TooManyApplyArguments),
860 }
861
862 for argument in apply.arguments.iter() {
864 scope = compile_expression(
865 compilation_context,
866 RichAst::new(argument.clone(), &metadata),
867 CompileMetadata::default(),
868 scope,
869 )?;
870 }
871
872 scope = compile_expression(
874 compilation_context,
875 RichAst::new(*apply.base, &metadata),
876 CompileMetadata::default(),
877 scope,
878 )?;
879 }
880
881 DatexExpressionData::PropertyAccess(property_access) => {
882 compilation_context.mark_has_non_static_value();
883
884 match &property_access.property.data {
886 DatexExpressionData::Text(key) if key.len() <= 255 => {
888 compile_text_property_access(compilation_context, key)
889 }
890 DatexExpressionData::Integer(index)
892 if let Some(index) = index.as_u32() =>
893 {
894 compile_index_property_access(compilation_context, index)
895 }
896 _ => {
897 scope = compile_dynamic_property_access(
898 compilation_context,
899 &property_access.property,
900 scope,
901 )?;
902 }
903 }
904
905 scope = compile_expression(
907 compilation_context,
908 RichAst::new(*property_access.base, &metadata),
909 CompileMetadata::default(),
910 scope,
911 )?;
912 }
913
914 DatexExpressionData::GenericInstantiation(generic_instantiation) => {
915 todo!("#674 Undescribed by author.")
917 }
918
919 DatexExpressionData::PropertyAssignment(property_assignment) => {
920 compilation_context.mark_has_non_static_value();
921
922 match &property_assignment.property.data {
924 DatexExpressionData::Text(key) if key.len() <= 255 => {
926 compile_text_property_assignment(compilation_context, key)
927 }
928 DatexExpressionData::Integer(index)
930 if let Some(index) = index.as_u32() =>
931 {
932 compile_index_property_assignment(
933 compilation_context,
934 index,
935 )
936 }
937 _ => {
938 scope = compile_dynamic_property_assignment(
939 compilation_context,
940 &property_assignment.property,
941 scope,
942 )?;
943 }
944 }
945
946 scope = compile_expression(
948 compilation_context,
949 RichAst::new(
950 *property_assignment.assigned_expression,
951 &metadata,
952 ),
953 CompileMetadata::default(),
954 scope,
955 )?;
956
957 scope = compile_expression(
959 compilation_context,
960 RichAst::new(*property_assignment.base, &metadata),
961 CompileMetadata::default(),
962 scope,
963 )?;
964 }
965
966 DatexExpressionData::VariableDeclaration(VariableDeclaration {
969 id,
970 name,
971 kind,
972 type_annotation,
973 init_expression: value,
974 }) => {
975 compilation_context.mark_has_non_static_value();
976
977 let virtual_slot_addr = scope.get_next_virtual_slot();
979 compilation_context
980 .append_instruction_code(InstructionCode::ALLOCATE_SLOT);
981 compilation_context.insert_virtual_slot_address(
982 VirtualSlot::local(virtual_slot_addr),
983 );
984 scope = compile_expression(
986 compilation_context,
987 RichAst::new(*value, &metadata),
988 CompileMetadata::default(),
989 scope,
990 )?;
991
992 let variable_model =
993 VariableModel::infer_from_ast_metadata_and_type(
994 &metadata.borrow(),
995 id,
996 kind,
997 compilation_context.execution_mode,
998 );
999
1000 let variable = match variable_model {
1002 VariableModel::VariableReference => {
1003 let virtual_slot_addr_for_var =
1005 scope.get_next_virtual_slot();
1006 compilation_context.append_instruction_code(
1007 InstructionCode::ALLOCATE_SLOT,
1008 );
1009 compilation_context.insert_virtual_slot_address(
1010 VirtualSlot::local(virtual_slot_addr_for_var),
1011 );
1012 compilation_context
1014 .append_instruction_code(InstructionCode::CREATE_REF);
1015 compilation_context
1017 .append_instruction_code(InstructionCode::GET_SLOT);
1018 compilation_context.insert_virtual_slot_address(
1019 VirtualSlot::local(virtual_slot_addr),
1020 );
1021
1022 Variable::new_variable_reference(
1023 name.clone(),
1024 kind,
1025 VirtualSlot::local(virtual_slot_addr_for_var),
1026 VirtualSlot::local(virtual_slot_addr),
1027 )
1028 }
1029 VariableModel::Constant => Variable::new_const(
1030 name.clone(),
1031 VirtualSlot::local(virtual_slot_addr),
1032 ),
1033 VariableModel::VariableSlot => Variable::new_variable_slot(
1034 name.clone(),
1035 kind,
1036 VirtualSlot::local(virtual_slot_addr),
1037 ),
1038 };
1039
1040 scope.register_variable_slot(variable);
1041 }
1042
1043 DatexExpressionData::GetReference(address) => {
1044 compilation_context.mark_has_non_static_value();
1045 append_get_ref(&mut compilation_context.buffer, &address)
1046 }
1047
1048 DatexExpressionData::VariableAssignment(VariableAssignment {
1050 operator,
1051 name,
1052 expression,
1053 ..
1054 }) => {
1055 compilation_context.mark_has_non_static_value();
1056 let (virtual_slot, kind) = scope
1058 .resolve_variable_name_to_virtual_slot(&name)
1059 .ok_or_else(|| {
1060 CompilerError::UndeclaredVariable(name.clone())
1061 })?;
1062
1063 if kind == VariableKind::Const {
1066 return Err(CompilerError::AssignmentToConst(name.clone()));
1067 }
1068
1069 match operator {
1070 AssignmentOperator::Assign => {
1071 info!(
1073 "append variable virtual slot: {virtual_slot:?}, name: {name}"
1074 );
1075 compilation_context
1076 .append_instruction_code(InstructionCode::SET_SLOT);
1077 }
1081 AssignmentOperator::AddAssign
1082 | AssignmentOperator::SubtractAssign => {
1083 compilation_context
1099 .append_instruction_code(InstructionCode::SET_SLOT);
1100 compilation_context.append_instruction_code(
1101 InstructionCode::from(&operator),
1102 );
1103 }
1104 op => core::todo!("#436 Handle assignment operator: {op:?}"),
1105 }
1106
1107 compilation_context.insert_virtual_slot_address(virtual_slot);
1108 scope = compile_expression(
1110 compilation_context,
1111 RichAst::new(*expression, &metadata),
1112 CompileMetadata::default(),
1113 scope,
1114 )?;
1115 }
1116
1117 DatexExpressionData::DerefAssignment(DerefAssignment {
1118 operator,
1119 deref_expression,
1120 assigned_expression,
1121 }) => {
1122 compilation_context.mark_has_non_static_value();
1123
1124 compilation_context
1125 .append_instruction_code(InstructionCode::SET_REFERENCE_VALUE);
1126
1127 compilation_context
1128 .append_instruction_code(InstructionCode::from(&operator));
1129
1130 scope = compile_expression(
1132 compilation_context,
1133 RichAst::new(*deref_expression, &metadata),
1134 CompileMetadata::default(),
1135 scope,
1136 )?;
1137
1138 scope = compile_expression(
1140 compilation_context,
1141 RichAst::new(*assigned_expression, &metadata),
1142 CompileMetadata::default(),
1143 scope,
1144 )?;
1145 }
1146
1147 DatexExpressionData::VariableAccess(VariableAccess {
1149 name, ..
1150 }) => {
1151 compilation_context.mark_has_non_static_value();
1152 let (virtual_slot, ..) = scope
1154 .resolve_variable_name_to_virtual_slot(&name)
1155 .ok_or_else(|| {
1156 CompilerError::UndeclaredVariable(name.clone())
1157 })?;
1158 compilation_context
1160 .append_instruction_code(InstructionCode::GET_SLOT);
1161 compilation_context.insert_virtual_slot_address(virtual_slot);
1162 }
1163
1164 DatexExpressionData::RemoteExecution(RemoteExecution {
1166 left: caller,
1167 right: script,
1168 }) => {
1169 compilation_context.mark_has_non_static_value();
1170
1171 compilation_context
1173 .append_instruction_code(InstructionCode::REMOTE_EXECUTION);
1174
1175 let mut execution_block_ctx = CompilationContext::new(
1177 Vec::with_capacity(256),
1178 vec![],
1179 ExecutionMode::Static,
1180 );
1181 let external_scope = compile_rich_ast(
1182 &mut execution_block_ctx,
1183 RichAst::new(*script, &metadata),
1184 CompilationScope::new_with_external_parent_scope(scope),
1185 )?;
1186 scope = external_scope
1188 .pop_external()
1189 .ok_or_else(|| CompilerError::ScopePopError)?;
1190
1191 let external_slots = execution_block_ctx.external_slots();
1192
1193 append_u32(
1196 &mut compilation_context.buffer,
1197 execution_block_ctx.buffer.len() as u32,
1198 );
1199 append_u32(
1201 &mut compilation_context.buffer,
1202 external_slots.len() as u32,
1203 );
1204 for slot in external_slots {
1205 compilation_context.insert_virtual_slot_address(slot.upgrade());
1206 }
1207
1208 compilation_context
1210 .buffer
1211 .extend_from_slice(&execution_block_ctx.buffer);
1212 scope = compile_expression(
1216 compilation_context,
1217 RichAst::new(*caller, &metadata),
1218 CompileMetadata::default(),
1219 scope,
1220 )?;
1221 }
1222
1223 DatexExpressionData::Slot(Slot::Named(name)) => {
1225 match name.as_str() {
1226 "endpoint" => {
1227 compilation_context.append_instruction_code(
1228 InstructionCode::GET_INTERNAL_SLOT,
1229 );
1230 append_u32(
1231 &mut compilation_context.buffer,
1232 InternalSlot::ENDPOINT as u32,
1233 );
1234 }
1235 "core" => append_get_ref(
1236 &mut compilation_context.buffer,
1237 &PointerAddress::from(CoreLibPointerId::Core),
1238 ),
1239 _ => {
1240 return Err(CompilerError::InvalidSlotName(name.clone()));
1242 }
1243 }
1244 }
1245
1246 DatexExpressionData::PointerAddress(address) => {
1248 append_get_ref(&mut compilation_context.buffer, &address);
1249 }
1250
1251 DatexExpressionData::CreateRef(create_ref) => {
1253 compilation_context.mark_has_non_static_value();
1254 compilation_context.append_instruction_code(
1255 match create_ref.mutability {
1256 ReferenceMutability::Immutable => {
1257 InstructionCode::CREATE_REF
1258 }
1259 ReferenceMutability::Mutable => {
1260 InstructionCode::CREATE_REF_MUT
1261 }
1262 },
1263 );
1264 scope = compile_expression(
1265 compilation_context,
1266 RichAst::new(*create_ref.expression, &metadata),
1267 CompileMetadata::default(),
1268 scope,
1269 )?;
1270 }
1271
1272 DatexExpressionData::TypeExpression(type_expression) => {
1273 compilation_context
1274 .append_instruction_code(InstructionCode::TYPE_EXPRESSION);
1275 scope = compile_type_expression(
1276 compilation_context,
1277 &type_expression,
1278 metadata,
1279 scope,
1280 )?;
1281 }
1282
1283 DatexExpressionData::Deref(deref) => {
1284 compilation_context.mark_has_non_static_value();
1285 compilation_context.append_instruction_code(InstructionCode::DEREF);
1286 scope = compile_expression(
1287 compilation_context,
1288 RichAst::new(*deref.expression, &metadata),
1289 CompileMetadata::default(),
1290 scope,
1291 )?;
1292 }
1293
1294 e => {
1295 println!("Unhandled expression in compiler: {:?}", e);
1296 return Err(CompilerError::UnexpectedTerm(Box::new(rich_ast.ast)));
1297 }
1298 }
1299
1300 Ok(scope)
1301}
1302
1303fn compile_key_value_entry(
1304 compilation_context: &mut CompilationContext,
1305 key: DatexExpression,
1306 value: DatexExpression,
1307 metadata: &Rc<RefCell<AstMetadata>>,
1308 mut scope: CompilationScope,
1309) -> Result<CompilationScope, CompilerError> {
1310 match key.data {
1311 DatexExpressionData::Text(text) => {
1313 append_key_string(&mut compilation_context.buffer, &text);
1314 }
1315 _ => {
1317 compilation_context
1318 .append_instruction_code(InstructionCode::KEY_VALUE_DYNAMIC);
1319 scope = compile_expression(
1320 compilation_context,
1321 RichAst::new(key, metadata),
1322 CompileMetadata::default(),
1323 scope,
1324 )?;
1325 }
1326 };
1327 scope = compile_expression(
1329 compilation_context,
1330 RichAst::new(value, metadata),
1331 CompileMetadata::default(),
1332 scope,
1333 )?;
1334 Ok(scope)
1335}
1336
1337fn compile_text_property_access(
1338 compilation_context: &mut CompilationContext,
1339 key: &str,
1340) {
1341 compilation_context
1342 .append_instruction_code(InstructionCode::GET_PROPERTY_TEXT);
1343 append_u8(&mut compilation_context.buffer, key.len() as u8);
1345 compilation_context.buffer.extend_from_slice(key.as_bytes());
1347}
1348
1349fn compile_text_property_assignment(
1350 compilation_context: &mut CompilationContext,
1351 key: &str,
1352) {
1353 compilation_context
1354 .append_instruction_code(InstructionCode::SET_PROPERTY_TEXT);
1355 append_u8(&mut compilation_context.buffer, key.len() as u8);
1357 compilation_context.buffer.extend_from_slice(key.as_bytes());
1359}
1360
1361fn compile_index_property_access(
1362 compilation_context: &mut CompilationContext,
1363 index: u32,
1364) {
1365 compilation_context
1366 .append_instruction_code(InstructionCode::GET_PROPERTY_INDEX);
1367 append_u32(&mut compilation_context.buffer, index);
1368}
1369
1370fn compile_index_property_assignment(
1371 compilation_context: &mut CompilationContext,
1372 index: u32,
1373) {
1374 compilation_context
1375 .append_instruction_code(InstructionCode::SET_PROPERTY_INDEX);
1376 append_u32(&mut compilation_context.buffer, index);
1377}
1378
1379fn compile_dynamic_property_access(
1380 compilation_context: &mut CompilationContext,
1381 key_expression: &DatexExpression,
1382 scope: CompilationScope,
1383) -> Result<CompilationScope, CompilerError> {
1384 compilation_context
1385 .append_instruction_code(InstructionCode::GET_PROPERTY_DYNAMIC);
1386 compile_expression(
1388 compilation_context,
1389 RichAst::new(
1390 key_expression.clone(),
1391 &Rc::new(RefCell::new(AstMetadata::default())),
1392 ),
1393 CompileMetadata::default(),
1394 scope,
1395 )
1396}
1397
1398fn compile_dynamic_property_assignment(
1399 compilation_context: &mut CompilationContext,
1400 key_expression: &DatexExpression,
1401 scope: CompilationScope,
1402) -> Result<CompilationScope, CompilerError> {
1403 compilation_context
1404 .append_instruction_code(InstructionCode::SET_PROPERTY_DYNAMIC);
1405 compile_expression(
1407 compilation_context,
1408 RichAst::new(
1409 key_expression.clone(),
1410 &Rc::new(RefCell::new(AstMetadata::default())),
1411 ),
1412 CompileMetadata::default(),
1413 scope,
1414 )
1415}
1416
1417#[cfg(test)]
1418pub mod tests {
1419 use super::{
1420 CompilationContext, CompileOptions, StaticValueOrDXB, compile_ast,
1421 compile_script, compile_script_or_return_static_value,
1422 compile_template, parse_datex_script_to_rich_ast_simple_error,
1423 };
1424 use crate::stdlib::assert_matches::assert_matches;
1425 use crate::stdlib::io::Read;
1426 use crate::stdlib::vec;
1427
1428 use crate::compiler::scope::CompilationScope;
1429 use crate::global::type_instruction_codes::TypeInstructionCode;
1430 use crate::libs::core::CoreLibPointerId;
1431 use crate::runtime::execution::ExecutionError;
1432 use crate::runtime::execution::context::{
1433 ExecutionContext, ExecutionMode, LocalExecutionContext,
1434 };
1435 use crate::values::core_values::integer::Integer;
1436 use crate::values::pointer::PointerAddress;
1437 use crate::values::value_container::ValueContainer;
1438 use crate::{
1439 global::instruction_codes::InstructionCode, logger::init_logger_debug,
1440 };
1441 use datex_core::compiler::error::CompilerError;
1442 use datex_core::values::core_values::integer::typed_integer::TypedInteger;
1443 use log::*;
1444
1445 fn compile_and_log(datex_script: &str) -> Vec<u8> {
1446 init_logger_debug();
1447 let (result, _) =
1448 compile_script(datex_script, CompileOptions::default()).unwrap();
1449 info!(
1450 "{:?}",
1451 result
1452 .iter()
1453 .map(|x| InstructionCode::try_from(*x).map(|x| x.to_string()))
1454 .map(|x| x.unwrap_or_else(|_| "Unknown".to_string()))
1455 .collect::<Vec<_>>()
1456 );
1457 result
1458 }
1459
1460 fn get_compilation_context(script: &str) -> CompilationContext {
1461 let mut options = CompileOptions::default();
1462 let ast =
1463 parse_datex_script_to_rich_ast_simple_error(script, &mut options)
1464 .unwrap();
1465
1466 let mut compilation_context = CompilationContext::new(
1467 Vec::with_capacity(256),
1468 vec![],
1469 options.compile_scope.execution_mode,
1470 );
1471 compile_ast(ast, &mut compilation_context, options).unwrap();
1472 compilation_context
1473 }
1474
1475 fn compile_datex_script_debug_unbounded(
1476 datex_script_parts: impl Iterator<Item = &'static str>,
1477 ) -> impl Iterator<Item = Vec<u8>> {
1478 let datex_script_parts = datex_script_parts.collect::<Vec<_>>();
1479 gen move {
1480 let mut compilation_scope =
1481 CompilationScope::new(ExecutionMode::unbounded());
1482 let len = datex_script_parts.len();
1483 for (index, script_part) in
1484 datex_script_parts.into_iter().enumerate()
1485 {
1486 if index == len - 1 {
1488 compilation_scope.mark_as_last_execution();
1489 }
1490 let (dxb, new_compilation_scope) = compile_script(
1491 script_part,
1492 CompileOptions::new_with_scope(compilation_scope),
1493 )
1494 .unwrap();
1495 compilation_scope = new_compilation_scope;
1496 yield dxb;
1497 }
1498 }
1499 }
1500
1501 fn assert_unbounded_input_matches_output(
1502 input: Vec<&'static str>,
1503 expected_output: Vec<Vec<u8>>,
1504 ) {
1505 let input = input.into_iter();
1506 let expected_output = expected_output.into_iter();
1507 for (result, expected) in
1508 compile_datex_script_debug_unbounded(input.into_iter())
1509 .zip(expected_output.into_iter())
1510 {
1511 assert_eq!(result, expected);
1512 }
1513 }
1514
1515 #[test]
1516 fn simple_multiplication() {
1517 init_logger_debug();
1518
1519 let lhs: u8 = 1;
1520 let rhs: u8 = 2;
1521 let datex_script = format!("{lhs}u8 * {rhs}u8"); let result = compile_and_log(&datex_script);
1523 assert_eq!(
1524 result,
1525 vec![
1526 InstructionCode::MULTIPLY.into(),
1527 InstructionCode::UINT_8.into(),
1528 lhs,
1529 InstructionCode::UINT_8.into(),
1530 rhs,
1531 ]
1532 );
1533 }
1534
1535 #[test]
1536 fn simple_multiplication_close() {
1537 init_logger_debug();
1538
1539 let lhs: u8 = 1;
1540 let rhs: u8 = 2;
1541 let datex_script = format!("{lhs}u8 * {rhs}u8;"); let result = compile_and_log(&datex_script);
1543 assert_eq!(
1544 result,
1545 vec![
1546 InstructionCode::SHORT_STATEMENTS.into(),
1547 1,
1548 1, InstructionCode::MULTIPLY.into(),
1550 InstructionCode::UINT_8.into(),
1551 lhs,
1552 InstructionCode::UINT_8.into(),
1553 rhs,
1554 ]
1555 );
1556 }
1557
1558 #[test]
1559 fn is_operator() {
1560 init_logger_debug();
1561
1562 let datex_script = "1u8 is 2u8".to_string();
1564 let result = compile_and_log(&datex_script);
1565 assert_eq!(
1566 result,
1567 vec![
1568 InstructionCode::IS.into(),
1569 InstructionCode::UINT_8.into(),
1570 1,
1571 InstructionCode::UINT_8.into(),
1572 2
1573 ]
1574 );
1575
1576 let datex_script =
1577 "const a = &mut 42u8; const b = &mut 69u8; a is b".to_string(); let result = compile_and_log(&datex_script);
1579 assert_eq!(
1580 result,
1581 vec![
1582 InstructionCode::SHORT_STATEMENTS.into(),
1583 3,
1584 0, InstructionCode::ALLOCATE_SLOT.into(),
1586 0,
1587 0,
1588 0,
1589 0,
1590 InstructionCode::CREATE_REF_MUT.into(),
1591 InstructionCode::UINT_8.into(),
1592 42,
1593 InstructionCode::ALLOCATE_SLOT.into(),
1595 1,
1596 0,
1597 0,
1598 0,
1599 InstructionCode::CREATE_REF_MUT.into(),
1600 InstructionCode::UINT_8.into(),
1601 69,
1602 InstructionCode::IS.into(),
1604 InstructionCode::GET_SLOT.into(),
1605 0,
1606 0,
1607 0,
1608 0, InstructionCode::GET_SLOT.into(),
1610 1,
1611 0,
1612 0,
1613 0, ]
1615 );
1616 }
1617
1618 #[test]
1619 fn equality_operator() {
1620 init_logger_debug();
1621
1622 let lhs: u8 = 1;
1623 let rhs: u8 = 2;
1624 let datex_script = format!("{lhs}u8 == {rhs}u8"); let result = compile_and_log(&datex_script);
1626 assert_eq!(
1627 result,
1628 vec![
1629 InstructionCode::STRUCTURAL_EQUAL.into(),
1630 InstructionCode::UINT_8.into(),
1631 lhs,
1632 InstructionCode::UINT_8.into(),
1633 rhs,
1634 ]
1635 );
1636
1637 let datex_script = format!("{lhs}u8 === {rhs}u8"); let result = compile_and_log(&datex_script);
1639 assert_eq!(
1640 result,
1641 vec![
1642 InstructionCode::EQUAL.into(),
1643 InstructionCode::UINT_8.into(),
1644 lhs,
1645 InstructionCode::UINT_8.into(),
1646 rhs,
1647 ]
1648 );
1649
1650 let datex_script = format!("{lhs}u8 != {rhs}u8"); let result = compile_and_log(&datex_script);
1652 assert_eq!(
1653 result,
1654 vec![
1655 InstructionCode::NOT_STRUCTURAL_EQUAL.into(),
1656 InstructionCode::UINT_8.into(),
1657 lhs,
1658 InstructionCode::UINT_8.into(),
1659 rhs,
1660 ]
1661 );
1662 let datex_script = format!("{lhs}u8 !== {rhs}u8"); let result = compile_and_log(&datex_script);
1664 assert_eq!(
1665 result,
1666 vec![
1667 InstructionCode::NOT_EQUAL.into(),
1668 InstructionCode::UINT_8.into(),
1669 lhs,
1670 InstructionCode::UINT_8.into(),
1671 rhs,
1672 ]
1673 );
1674 }
1675
1676 #[test]
1677 fn simple_addition() {
1678 init_logger_debug();
1679
1680 let lhs: u8 = 1;
1681 let rhs: u8 = 2;
1682 let datex_script = format!("{lhs}u8 + {rhs}u8"); let result = compile_and_log(&datex_script);
1684 assert_eq!(
1685 result,
1686 vec![
1687 InstructionCode::ADD.into(),
1688 InstructionCode::UINT_8.into(),
1689 lhs,
1690 InstructionCode::UINT_8.into(),
1691 rhs
1692 ]
1693 );
1694
1695 let datex_script = format!("{lhs}u8 + {rhs}u8;"); let result = compile_and_log(&datex_script);
1697 assert_eq!(
1698 result,
1699 vec![
1700 InstructionCode::SHORT_STATEMENTS.into(),
1701 1,
1702 1, InstructionCode::ADD.into(),
1704 InstructionCode::UINT_8.into(),
1705 lhs,
1706 InstructionCode::UINT_8.into(),
1707 rhs,
1708 ]
1709 );
1710 }
1711
1712 #[test]
1713 fn multi_addition() {
1714 init_logger_debug();
1715
1716 let op1: u8 = 1;
1717 let op2: u8 = 2;
1718 let op3: u8 = 3;
1719 let op4: u8 = 4;
1720
1721 let datex_script = format!("{op1}u8 + {op2}u8 + {op3}u8 + {op4}u8"); let result = compile_and_log(&datex_script);
1723 assert_eq!(
1724 result,
1725 vec![
1726 InstructionCode::ADD.into(),
1727 InstructionCode::ADD.into(),
1728 InstructionCode::ADD.into(),
1729 InstructionCode::UINT_8.into(),
1730 op1,
1731 InstructionCode::UINT_8.into(),
1732 op2,
1733 InstructionCode::UINT_8.into(),
1734 op3,
1735 InstructionCode::UINT_8.into(),
1736 op4,
1737 ]
1738 );
1739 }
1740
1741 #[test]
1742 fn mixed_calculation() {
1743 init_logger_debug();
1744
1745 let op1: u8 = 1;
1746 let op2: u8 = 2;
1747 let op3: u8 = 3;
1748 let op4: u8 = 4;
1749
1750 let datex_script = format!("{op1}u8 * {op2}u8 + {op3}u8 * {op4}u8"); let result = compile_and_log(&datex_script);
1752 assert_eq!(
1753 result,
1754 vec![
1755 InstructionCode::ADD.into(),
1756 InstructionCode::MULTIPLY.into(),
1757 InstructionCode::UINT_8.into(),
1758 op1,
1759 InstructionCode::UINT_8.into(),
1760 op2,
1761 InstructionCode::MULTIPLY.into(),
1762 InstructionCode::UINT_8.into(),
1763 op3,
1764 InstructionCode::UINT_8.into(),
1765 op4,
1766 ]
1767 );
1768 }
1769
1770 #[test]
1771 fn complex_addition() {
1772 init_logger_debug();
1773
1774 let a: u8 = 1;
1775 let b: u8 = 2;
1776 let c: u8 = 3;
1777 let datex_script = format!("{a}u8 + ({b}u8 + {c}u8)"); let result = compile_and_log(&datex_script);
1779
1780 assert_eq!(
1781 result,
1782 vec![
1783 InstructionCode::ADD.into(),
1784 InstructionCode::UINT_8.into(),
1785 a,
1786 InstructionCode::ADD.into(),
1787 InstructionCode::UINT_8.into(),
1788 b,
1789 InstructionCode::UINT_8.into(),
1790 c,
1791 ]
1792 );
1793 }
1794
1795 #[test]
1796 fn complex_addition_and_subtraction() {
1797 init_logger_debug();
1798
1799 let a: u8 = 1;
1800 let b: u8 = 2;
1801 let c: u8 = 3;
1802 let datex_script = format!("{a}u8 + ({b}u8 - {c}u8)"); let result = compile_and_log(&datex_script);
1804 assert_eq!(
1805 result,
1806 vec![
1807 InstructionCode::ADD.into(),
1808 InstructionCode::UINT_8.into(),
1809 a,
1810 InstructionCode::SUBTRACT.into(),
1811 InstructionCode::UINT_8.into(),
1812 b,
1813 InstructionCode::UINT_8.into(),
1814 c,
1815 ]
1816 );
1817 }
1818
1819 #[test]
1820 fn integer_u8() {
1821 init_logger_debug();
1822 let val = 42;
1823 let datex_script = format!("{val}u8"); let result = compile_and_log(&datex_script);
1825 assert_eq!(result, vec![InstructionCode::UINT_8.into(), val,]);
1826 }
1827
1828 #[test]
1830 fn decimal() {
1831 init_logger_debug();
1832 let datex_script = "42.0";
1833 let result = compile_and_log(datex_script);
1834 let bytes = 42_i16.to_le_bytes();
1835
1836 let mut expected: Vec<u8> =
1837 vec![InstructionCode::DECIMAL_AS_INT_16.into()];
1838 expected.extend(bytes);
1839
1840 assert_eq!(result, expected);
1841 }
1842
1843 #[test]
1845 fn short_text() {
1846 init_logger_debug();
1847 let val = "unyt";
1848 let datex_script = format!("\"{val}\""); let result = compile_and_log(&datex_script);
1850 let mut expected: Vec<u8> =
1851 vec![InstructionCode::SHORT_TEXT.into(), val.len() as u8];
1852 expected.extend(val.bytes());
1853 assert_eq!(result, expected);
1854 }
1855
1856 #[test]
1858 fn empty_list() {
1859 init_logger_debug();
1860 let datex_script = "[]";
1862 let result = compile_and_log(datex_script);
1864 let expected: Vec<u8> = vec![
1865 InstructionCode::SHORT_LIST.into(),
1866 0, ];
1868 assert_eq!(result, expected);
1869 }
1870
1871 #[test]
1873 fn single_element_list() {
1874 init_logger_debug();
1875 let datex_script = "[42u8]";
1877 let result = compile_and_log(datex_script);
1878 assert_eq!(
1879 result,
1880 vec![
1881 InstructionCode::SHORT_LIST.into(),
1882 1, InstructionCode::UINT_8.into(),
1884 42,
1885 ]
1886 );
1887 }
1888
1889 #[test]
1891 fn multi_element_list() {
1892 init_logger_debug();
1893 let datex_script = "[1u8, 2u8, 3u8]";
1894 let result = compile_and_log(datex_script);
1895 assert_eq!(
1896 result,
1897 vec![
1898 InstructionCode::SHORT_LIST.into(),
1899 3, InstructionCode::UINT_8.into(),
1901 1,
1902 InstructionCode::UINT_8.into(),
1903 2,
1904 InstructionCode::UINT_8.into(),
1905 3,
1906 ]
1907 );
1908
1909 let datex_script = "[1u8, 2u8, 3u8,]";
1911 let result = compile_and_log(datex_script);
1912 assert_eq!(
1913 result,
1914 vec![
1915 InstructionCode::SHORT_LIST.into(),
1916 3, InstructionCode::UINT_8.into(),
1918 1,
1919 InstructionCode::UINT_8.into(),
1920 2,
1921 InstructionCode::UINT_8.into(),
1922 3,
1923 ]
1924 );
1925 }
1926
1927 #[test]
1929 fn list_with_expressions() {
1930 init_logger_debug();
1931 let datex_script = "[1u8 + 2u8, 3u8 * 4u8]";
1932 let result = compile_and_log(datex_script);
1933 assert_eq!(
1934 result,
1935 vec![
1936 InstructionCode::SHORT_LIST.into(),
1937 2, InstructionCode::ADD.into(),
1939 InstructionCode::UINT_8.into(),
1940 1,
1941 InstructionCode::UINT_8.into(),
1942 2,
1943 InstructionCode::MULTIPLY.into(),
1944 InstructionCode::UINT_8.into(),
1945 3,
1946 InstructionCode::UINT_8.into(),
1947 4,
1948 ]
1949 );
1950 }
1951
1952 #[test]
1954 fn nested_lists() {
1955 init_logger_debug();
1956 let datex_script = "[1u8, [2u8, 3u8], 4u8]";
1957 let result = compile_and_log(datex_script);
1958 assert_eq!(
1959 result,
1960 vec![
1961 InstructionCode::SHORT_LIST.into(),
1962 3, InstructionCode::UINT_8.into(),
1964 1,
1965 InstructionCode::SHORT_LIST.into(),
1966 2, InstructionCode::UINT_8.into(),
1968 2,
1969 InstructionCode::UINT_8.into(),
1970 3,
1971 InstructionCode::UINT_8.into(),
1972 4,
1973 ]
1974 );
1975 }
1976
1977 #[test]
1979 fn map_with_text_key() {
1980 init_logger_debug();
1981 let datex_script = "{\"key\": 42u8}";
1982 let result = compile_and_log(datex_script);
1983 let expected = vec![
1984 InstructionCode::SHORT_MAP.into(),
1985 1, InstructionCode::KEY_VALUE_SHORT_TEXT.into(),
1987 3, b'k',
1989 b'e',
1990 b'y',
1991 InstructionCode::UINT_8.into(),
1992 42,
1993 ];
1994 assert_eq!(result, expected);
1995 }
1996
1997 #[test]
1999 fn map_integer_key() {
2000 init_logger_debug();
2001 let datex_script = "{(10u8): 42u8}";
2002 let result = compile_and_log(datex_script);
2003 let expected = vec![
2004 InstructionCode::SHORT_MAP.into(),
2005 1, InstructionCode::KEY_VALUE_DYNAMIC.into(),
2007 InstructionCode::UINT_8.into(),
2008 10,
2009 InstructionCode::UINT_8.into(),
2010 42,
2011 ];
2012 assert_eq!(result, expected);
2013 }
2014
2015 #[test]
2017 fn map_with_long_text_key() {
2018 init_logger_debug();
2019 let long_key = "a".repeat(300);
2020 let datex_script = format!("{{\"{long_key}\": 42u8}}");
2021 let result = compile_and_log(&datex_script);
2022 let mut expected: Vec<u8> = vec![
2023 InstructionCode::SHORT_MAP.into(),
2024 1, InstructionCode::KEY_VALUE_DYNAMIC.into(),
2026 InstructionCode::TEXT.into(),
2027 ];
2028 expected.extend((long_key.len() as u32).to_le_bytes());
2029 expected.extend(long_key.as_bytes());
2030 expected.extend(vec![InstructionCode::UINT_8.into(), 42]);
2031 assert_eq!(result, expected);
2032 }
2033
2034 #[test]
2036 fn map_with_dynamic_key() {
2037 init_logger_debug();
2038 let datex_script = "{(1u8 + 2u8): 42u8}";
2039 let result = compile_and_log(datex_script);
2040 let expected = [
2041 InstructionCode::SHORT_MAP.into(),
2042 1, InstructionCode::KEY_VALUE_DYNAMIC.into(),
2044 InstructionCode::ADD.into(),
2045 InstructionCode::UINT_8.into(),
2046 1,
2047 InstructionCode::UINT_8.into(),
2048 2,
2049 InstructionCode::UINT_8.into(),
2050 42,
2051 ];
2052 assert_eq!(result, expected);
2053 }
2054
2055 #[test]
2057 fn map_with_multiple_keys() {
2058 init_logger_debug();
2059 let datex_script = "{key: 42u8, (4u8): 43u8, (1u8 + 2u8): 44u8}";
2060 let result = compile_and_log(datex_script);
2061 let expected = vec![
2062 InstructionCode::SHORT_MAP.into(),
2063 3, InstructionCode::KEY_VALUE_SHORT_TEXT.into(),
2065 3, b'k',
2067 b'e',
2068 b'y',
2069 InstructionCode::UINT_8.into(),
2070 42,
2071 InstructionCode::KEY_VALUE_DYNAMIC.into(),
2072 InstructionCode::UINT_8.into(),
2073 4,
2074 InstructionCode::UINT_8.into(),
2075 43,
2076 InstructionCode::KEY_VALUE_DYNAMIC.into(),
2077 InstructionCode::ADD.into(),
2078 InstructionCode::UINT_8.into(),
2079 1,
2080 InstructionCode::UINT_8.into(),
2081 2,
2082 InstructionCode::UINT_8.into(),
2083 44,
2084 ];
2085 assert_eq!(result, expected);
2086 }
2087
2088 #[test]
2090 fn empty_map() {
2091 init_logger_debug();
2092 let datex_script = "{}";
2093 let result = compile_and_log(datex_script);
2094 let expected: Vec<u8> = vec![
2095 InstructionCode::SHORT_MAP.into(),
2096 0, ];
2098 assert_eq!(result, expected);
2099 }
2100
2101 #[test]
2102 fn allocate_slot() {
2103 init_logger_debug();
2104 let script = "const a = 42u8";
2105 let result = compile_and_log(script);
2106 assert_eq!(
2107 result,
2108 vec![
2109 InstructionCode::ALLOCATE_SLOT.into(),
2110 0,
2112 0,
2113 0,
2114 0,
2115 InstructionCode::UINT_8.into(),
2116 42,
2117 ]
2118 );
2119 }
2120
2121 #[test]
2122 fn allocate_slot_with_value() {
2123 init_logger_debug();
2124 let script = "const a = 42u8; a + 1u8";
2125 let result = compile_and_log(script);
2126 assert_eq!(
2127 result,
2128 vec![
2129 InstructionCode::SHORT_STATEMENTS.into(),
2130 2,
2131 0, InstructionCode::ALLOCATE_SLOT.into(),
2133 0,
2135 0,
2136 0,
2137 0,
2138 InstructionCode::UINT_8.into(),
2139 42,
2140 InstructionCode::ADD.into(),
2141 InstructionCode::GET_SLOT.into(),
2142 0,
2144 0,
2145 0,
2146 0,
2147 InstructionCode::UINT_8.into(),
2148 1,
2149 ]
2150 );
2151 }
2152
2153 #[test]
2154 fn allocate_scoped_slots() {
2155 init_logger_debug();
2156 let script = "const a = 42u8; (const a = 43u8; a); a";
2157 let result = compile_and_log(script);
2158 assert_eq!(
2159 result,
2160 vec![
2161 InstructionCode::SHORT_STATEMENTS.into(),
2162 3,
2163 0, InstructionCode::ALLOCATE_SLOT.into(),
2165 0,
2166 0,
2167 0,
2168 0,
2169 InstructionCode::UINT_8.into(),
2170 42,
2171 InstructionCode::SHORT_STATEMENTS.into(),
2172 2,
2173 0, InstructionCode::ALLOCATE_SLOT.into(),
2175 1,
2176 0,
2177 0,
2178 0,
2179 InstructionCode::UINT_8.into(),
2180 43,
2181 InstructionCode::GET_SLOT.into(),
2182 1,
2183 0,
2184 0,
2185 0,
2186 InstructionCode::DROP_SLOT.into(),
2187 1,
2188 0,
2189 0,
2190 0,
2191 InstructionCode::GET_SLOT.into(),
2192 0,
2194 0,
2195 0,
2196 0,
2197 ]
2198 );
2199 }
2200
2201 #[test]
2202 fn allocate_scoped_slots_with_parent_variables() {
2203 init_logger_debug();
2204 let script =
2205 "const a = 42u8; const b = 41u8; (const a = 43u8; a; b); a";
2206 let result = compile_and_log(script);
2207 assert_eq!(
2208 result,
2209 vec![
2210 InstructionCode::SHORT_STATEMENTS.into(),
2211 4,
2212 0, InstructionCode::ALLOCATE_SLOT.into(),
2214 0,
2215 0,
2216 0,
2217 0,
2218 InstructionCode::UINT_8.into(),
2219 42,
2220 InstructionCode::ALLOCATE_SLOT.into(),
2221 1,
2222 0,
2223 0,
2224 0,
2225 InstructionCode::UINT_8.into(),
2226 41,
2227 InstructionCode::SHORT_STATEMENTS.into(),
2228 3,
2229 0, InstructionCode::ALLOCATE_SLOT.into(),
2231 2,
2232 0,
2233 0,
2234 0,
2235 InstructionCode::UINT_8.into(),
2236 43,
2237 InstructionCode::GET_SLOT.into(),
2238 2,
2239 0,
2240 0,
2241 0,
2242 InstructionCode::GET_SLOT.into(),
2243 1,
2244 0,
2245 0,
2246 0,
2247 InstructionCode::DROP_SLOT.into(),
2248 2,
2249 0,
2250 0,
2251 0,
2252 InstructionCode::GET_SLOT.into(),
2253 0,
2255 0,
2256 0,
2257 0,
2258 ]
2259 );
2260 }
2261
2262 #[test]
2263 fn allocate_ref() {
2264 init_logger_debug();
2265 let script = "const a = &mut 42u8";
2266 let result = compile_and_log(script);
2267 assert_eq!(
2268 result,
2269 vec![
2270 InstructionCode::ALLOCATE_SLOT.into(),
2271 0,
2273 0,
2274 0,
2275 0,
2276 InstructionCode::CREATE_REF_MUT.into(),
2277 InstructionCode::UINT_8.into(),
2278 42,
2279 ]
2280 );
2281 }
2282
2283 #[test]
2284 fn read_ref() {
2285 init_logger_debug();
2286 let script = "const a = &mut 42u8; a";
2287 let result = compile_and_log(script);
2288 assert_eq!(
2289 result,
2290 vec![
2291 InstructionCode::SHORT_STATEMENTS.into(),
2292 2,
2293 0, InstructionCode::ALLOCATE_SLOT.into(),
2295 0,
2297 0,
2298 0,
2299 0,
2300 InstructionCode::CREATE_REF_MUT.into(),
2301 InstructionCode::UINT_8.into(),
2302 42,
2303 InstructionCode::GET_SLOT.into(),
2304 0,
2306 0,
2307 0,
2308 0,
2309 ]
2310 );
2311 }
2312
2313 #[test]
2314 fn compile() {
2315 init_logger_debug();
2316 let result = compile_template(
2317 "? + ?",
2318 &[
2319 TypedInteger::from(1u8).into(),
2320 TypedInteger::from(2u8).into(),
2321 ],
2322 CompileOptions::default(),
2323 );
2324 assert_eq!(
2325 result.unwrap().0,
2326 vec![
2327 InstructionCode::ADD.into(),
2328 InstructionCode::UINT_8.into(),
2329 1,
2330 InstructionCode::UINT_8.into(),
2331 2
2332 ]
2333 );
2334 }
2335
2336 #[test]
2337 fn compile_macro() {
2338 init_logger_debug();
2339 let a = TypedInteger::from(1u8);
2340 let result = compile!("?", a);
2341 assert_eq!(result.unwrap().0, vec![InstructionCode::UINT_8.into(), 1,]);
2342 }
2343
2344 #[test]
2345 fn compile_macro_multi() {
2346 init_logger_debug();
2347 let result =
2348 compile!("? + ?", TypedInteger::from(1u8), TypedInteger::from(2u8));
2349 assert_eq!(
2350 result.unwrap().0,
2351 vec![
2352 InstructionCode::ADD.into(),
2353 InstructionCode::UINT_8.into(),
2354 1,
2355 InstructionCode::UINT_8.into(),
2356 2
2357 ]
2358 );
2359 }
2360
2361 fn get_json_test_string(file_path: &str) -> String {
2362 let file_path = format!("benches/json/{file_path}");
2364 let file_path = std::path::Path::new(&file_path);
2365 let file =
2366 std::fs::File::open(file_path).expect("Failed to open test.json");
2367 let mut reader = crate::stdlib::io::BufReader::new(file);
2368 let mut json_string = String::new();
2369 reader
2370 .read_to_string(&mut json_string)
2371 .expect("Failed to read test.json");
2372 json_string
2373 }
2374
2375 #[test]
2376 fn json_to_dxb_large_file() {
2377 let json = get_json_test_string("test3.json");
2378 let _ = compile_script(&json, CompileOptions::default())
2379 .expect("Failed to parse JSON string");
2380 }
2381
2382 #[test]
2383 fn static_value_detection() {
2384 init_logger_debug();
2385
2386 let script = "1 + 2";
2388 let compilation_scope = get_compilation_context(script);
2389 assert!(compilation_scope.has_non_static_value);
2390
2391 let script = "1 2";
2392 let compilation_scope = get_compilation_context(script);
2393 assert!(compilation_scope.has_non_static_value);
2394
2395 let script = "1;2";
2396 let compilation_scope = get_compilation_context(script);
2397 assert!(compilation_scope.has_non_static_value);
2398
2399 let script = r#"{("x" + "y"): 1}"#;
2400 let compilation_scope = get_compilation_context(script);
2401 assert!(compilation_scope.has_non_static_value);
2402
2403 let script = "1";
2405 let compilation_scope = get_compilation_context(script);
2406 assert!(!compilation_scope.has_non_static_value);
2407
2408 let script = "[]";
2409 let compilation_scope = get_compilation_context(script);
2410 assert!(!compilation_scope.has_non_static_value);
2411
2412 let script = "{}";
2413 let compilation_scope = get_compilation_context(script);
2414 assert!(!compilation_scope.has_non_static_value);
2415
2416 let script = "[1,2,3]";
2417 let compilation_scope = get_compilation_context(script);
2418 assert!(!compilation_scope.has_non_static_value);
2419
2420 let script = "{a: 2}";
2421 let compilation_scope = get_compilation_context(script);
2422 assert!(!compilation_scope.has_non_static_value);
2423
2424 let script = "-42";
2426 let compilation_scope = get_compilation_context(script);
2427 assert!(!compilation_scope.has_non_static_value);
2428 }
2429
2430 #[test]
2431 fn compile_auto_static_value_detection() {
2432 let script = "1u8";
2433 let (res, _) = compile_script_or_return_static_value(
2434 script,
2435 CompileOptions::default(),
2436 )
2437 .unwrap();
2438 assert_matches!(
2439 res,
2440 StaticValueOrDXB::StaticValue(val) if val == Some(TypedInteger::from(1u8).into())
2441 );
2442
2443 let script = "1u8 + 2u8";
2444 let (res, _) = compile_script_or_return_static_value(
2445 script,
2446 CompileOptions::default(),
2447 )
2448 .unwrap();
2449 assert_matches!(
2450 res,
2451 StaticValueOrDXB::DXB(code) if code == vec![
2452 InstructionCode::ADD.into(),
2453 InstructionCode::UINT_8.into(),
2454 1,
2455 InstructionCode::UINT_8.into(),
2456 2,
2457 ]
2458 );
2459 }
2460
2461 #[test]
2462 fn remote_execution() {
2463 let script = "42u8 :: 43u8";
2464 let (res, _) =
2465 compile_script(script, CompileOptions::default()).unwrap();
2466 assert_eq!(
2467 res,
2468 vec![
2469 InstructionCode::REMOTE_EXECUTION.into(),
2470 2,
2473 0,
2474 0,
2475 0,
2476 0,
2478 0,
2479 0,
2480 0,
2481 InstructionCode::UINT_8.into(),
2483 43,
2484 InstructionCode::UINT_8.into(),
2487 42,
2488 ]
2489 );
2490 }
2491
2492 #[test]
2493 fn remote_execution_expression() {
2494 let script = "42u8 :: 1u8 + 2u8";
2495 let (res, _) =
2496 compile_script(script, CompileOptions::default()).unwrap();
2497 assert_eq!(
2498 res,
2499 vec![
2500 InstructionCode::REMOTE_EXECUTION.into(),
2501 5,
2504 0,
2505 0,
2506 0,
2507 0,
2509 0,
2510 0,
2511 0,
2512 InstructionCode::ADD.into(),
2514 InstructionCode::UINT_8.into(),
2515 1,
2516 InstructionCode::UINT_8.into(),
2517 2,
2518 InstructionCode::UINT_8.into(),
2521 42,
2522 ]
2523 );
2524 }
2525
2526 #[test]
2527 fn remote_execution_injected_const() {
2528 init_logger_debug();
2529 let script = "const x = 42u8; 1u8 :: x";
2530 let (res, _) =
2531 compile_script(script, CompileOptions::default()).unwrap();
2532 assert_eq!(
2533 res,
2534 vec![
2535 InstructionCode::SHORT_STATEMENTS.into(),
2536 2,
2537 0, InstructionCode::ALLOCATE_SLOT.into(),
2539 0,
2541 0,
2542 0,
2543 0,
2544 InstructionCode::UINT_8.into(),
2545 42,
2546 InstructionCode::REMOTE_EXECUTION.into(),
2547 5,
2550 0,
2551 0,
2552 0,
2553 1,
2555 0,
2556 0,
2557 0,
2558 0,
2560 0,
2561 0,
2562 0,
2563 InstructionCode::GET_SLOT.into(),
2565 0,
2567 0,
2568 0,
2569 0,
2570 InstructionCode::UINT_8.into(),
2573 1,
2574 ]
2575 );
2576 }
2577
2578 #[test]
2579 fn remote_execution_injected_var() {
2580 init_logger_debug();
2581 let script = "var x = 42u8; 1u8 :: x; x = 43u8;";
2584 let (res, _) =
2585 compile_script(script, CompileOptions::default()).unwrap();
2586 assert_eq!(
2587 res,
2588 vec![
2589 InstructionCode::SHORT_STATEMENTS.into(),
2590 3,
2591 1, InstructionCode::ALLOCATE_SLOT.into(),
2593 0,
2595 0,
2596 0,
2597 0,
2598 InstructionCode::UINT_8.into(),
2599 42,
2600 InstructionCode::ALLOCATE_SLOT.into(),
2601 1,
2603 0,
2604 0,
2605 0,
2606 InstructionCode::CREATE_REF.into(),
2608 InstructionCode::GET_SLOT.into(),
2610 0,
2612 0,
2613 0,
2614 0,
2615 InstructionCode::REMOTE_EXECUTION.into(),
2616 5,
2619 0,
2620 0,
2621 0,
2622 1,
2624 0,
2625 0,
2626 0,
2627 0,
2629 0,
2630 0,
2631 0,
2632 InstructionCode::GET_SLOT.into(),
2634 0,
2636 0,
2637 0,
2638 0,
2639 InstructionCode::UINT_8.into(),
2642 1,
2643 InstructionCode::SET_SLOT.into(),
2646 0,
2648 0,
2649 0,
2650 0,
2651 InstructionCode::UINT_8.into(),
2652 43,
2653 ]
2654 );
2655 }
2656
2657 #[test]
2658 fn remote_execution_injected_consts() {
2659 let script = "const x = 42u8; const y = 69u8; 1u8 :: x + y";
2660 let (res, _) =
2661 compile_script(script, CompileOptions::default()).unwrap();
2662 assert_eq!(
2663 res,
2664 vec![
2665 InstructionCode::SHORT_STATEMENTS.into(),
2666 3,
2667 0, InstructionCode::ALLOCATE_SLOT.into(),
2669 0,
2671 0,
2672 0,
2673 0,
2674 InstructionCode::UINT_8.into(),
2675 42,
2676 InstructionCode::ALLOCATE_SLOT.into(),
2677 1,
2679 0,
2680 0,
2681 0,
2682 InstructionCode::UINT_8.into(),
2683 69,
2684 InstructionCode::REMOTE_EXECUTION.into(),
2685 11,
2688 0,
2689 0,
2690 0,
2691 2,
2693 0,
2694 0,
2695 0,
2696 0,
2698 0,
2699 0,
2700 0,
2701 1,
2703 0,
2704 0,
2705 0,
2706 InstructionCode::ADD.into(),
2708 InstructionCode::GET_SLOT.into(),
2709 0,
2711 0,
2712 0,
2713 0,
2714 InstructionCode::GET_SLOT.into(),
2715 1,
2717 0,
2718 0,
2719 0,
2720 InstructionCode::UINT_8.into(),
2723 1,
2724 ]
2725 );
2726 }
2727
2728 #[test]
2729 fn remote_execution_shadow_const() {
2730 let script =
2731 "const x = 42u8; const y = 69u8; 1u8 :: (const x = 5u8; x + y)";
2732 let (res, _) =
2733 compile_script(script, CompileOptions::default()).unwrap();
2734 assert_eq!(
2735 res,
2736 vec![
2737 InstructionCode::SHORT_STATEMENTS.into(),
2738 3,
2739 0, InstructionCode::ALLOCATE_SLOT.into(),
2741 0,
2743 0,
2744 0,
2745 0,
2746 InstructionCode::UINT_8.into(),
2747 42,
2748 InstructionCode::ALLOCATE_SLOT.into(),
2749 1,
2751 0,
2752 0,
2753 0,
2754 InstructionCode::UINT_8.into(),
2755 69,
2756 InstructionCode::REMOTE_EXECUTION.into(),
2757 21,
2760 0,
2761 0,
2762 0,
2763 1,
2765 0,
2766 0,
2767 0,
2768 1,
2770 0,
2771 0,
2772 0,
2773 InstructionCode::SHORT_STATEMENTS.into(),
2774 2,
2775 0, InstructionCode::ALLOCATE_SLOT.into(),
2778 1,
2780 0,
2781 0,
2782 0,
2783 InstructionCode::UINT_8.into(),
2784 5,
2785 InstructionCode::ADD.into(),
2787 InstructionCode::GET_SLOT.into(),
2788 1,
2790 0,
2791 0,
2792 0,
2793 InstructionCode::GET_SLOT.into(),
2794 0,
2796 0,
2797 0,
2798 0,
2799 InstructionCode::UINT_8.into(),
2802 1,
2803 ]
2804 );
2805 }
2806
2807 #[test]
2808 fn remote_execution_nested() {
2809 let script = "const x = 42u8; (1u8 :: (2u8 :: x))";
2810 let (res, _) =
2811 compile_script(script, CompileOptions::default()).unwrap();
2812
2813 assert_eq!(
2814 res,
2815 vec![
2816 InstructionCode::SHORT_STATEMENTS.into(),
2817 2,
2818 0, InstructionCode::ALLOCATE_SLOT.into(),
2820 0,
2822 0,
2823 0,
2824 0,
2825 InstructionCode::UINT_8.into(),
2826 42,
2827 InstructionCode::REMOTE_EXECUTION.into(),
2828 20,
2831 0,
2832 0,
2833 0,
2834 1,
2836 0,
2837 0,
2838 0,
2839 0,
2841 0,
2842 0,
2843 0,
2844 InstructionCode::REMOTE_EXECUTION.into(),
2846 5,
2849 0,
2850 0,
2851 0,
2852 1,
2854 0,
2855 0,
2856 0,
2857 0,
2859 0,
2860 0,
2861 0,
2862 InstructionCode::GET_SLOT.into(),
2863 0,
2865 0,
2866 0,
2867 0,
2868 InstructionCode::UINT_8.into(),
2871 2,
2872 InstructionCode::UINT_8.into(),
2875 1,
2876 ]
2877 );
2878 }
2879
2880 #[test]
2881 fn remote_execution_nested2() {
2882 let script = "const x = 42u8; (1u8 :: (x :: x))";
2883 let (res, _) =
2884 compile_script(script, CompileOptions::default()).unwrap();
2885
2886 assert_eq!(
2887 res,
2888 vec![
2889 InstructionCode::SHORT_STATEMENTS.into(),
2890 2,
2891 0, InstructionCode::ALLOCATE_SLOT.into(),
2893 0,
2895 0,
2896 0,
2897 0,
2898 InstructionCode::UINT_8.into(),
2899 42,
2900 InstructionCode::REMOTE_EXECUTION.into(),
2901 23,
2904 0,
2905 0,
2906 0,
2907 1,
2909 0,
2910 0,
2911 0,
2912 0,
2914 0,
2915 0,
2916 0,
2917 InstructionCode::REMOTE_EXECUTION.into(),
2919 5,
2922 0,
2923 0,
2924 0,
2925 1,
2927 0,
2928 0,
2929 0,
2930 0,
2932 0,
2933 0,
2934 0,
2935 InstructionCode::GET_SLOT.into(),
2936 0,
2938 0,
2939 0,
2940 0,
2941 InstructionCode::GET_SLOT.into(),
2944 0,
2945 0,
2946 0,
2947 0,
2948 InstructionCode::UINT_8.into(),
2951 1,
2952 ]
2953 );
2954 }
2955
2956 #[test]
2957 fn assignment_to_const() {
2958 init_logger_debug();
2959 let script = "const a = 42; a = 43";
2960 let result = compile_script(script, CompileOptions::default())
2961 .map_err(|e| e.error);
2962 assert_matches!(result, Err(CompilerError::AssignmentToConst { .. }));
2963 }
2964
2965 #[test]
2966 fn assignment_to_const_mut() {
2967 init_logger_debug();
2968 let script = "const a = &mut 42; a = 43";
2969 let result = compile_script(script, CompileOptions::default())
2970 .map_err(|e| e.error);
2971 assert_matches!(result, Err(CompilerError::AssignmentToConst { .. }));
2972 }
2973
2974 #[test]
2975 fn internal_assignment_to_const_mut() {
2976 init_logger_debug();
2977 let script = "const a = &mut 42; *a = 43";
2978 let result = compile_script(script, CompileOptions::default());
2979 assert_matches!(result, Ok(_));
2980 }
2981
2982 #[test]
2983 fn addition_to_const_mut_ref() {
2984 init_logger_debug();
2985 let script = "const a = &mut 42; *a += 1;";
2986 let result = compile_script(script, CompileOptions::default());
2987 assert_matches!(result, Ok(_));
2988 }
2989
2990 #[test]
2991 fn addition_to_const_variable() {
2992 init_logger_debug();
2993 let script = "const a = 42; a += 1";
2994 let result = compile_script(script, CompileOptions::default())
2995 .map_err(|e| e.error);
2996 assert_matches!(result, Err(CompilerError::AssignmentToConst { .. }));
2997 }
2998
2999 #[test]
3000 fn internal_slot_endpoint() {
3001 let script = "#endpoint";
3002 let (res, _) =
3003 compile_script(script, CompileOptions::default()).unwrap();
3004 assert_eq!(
3005 res,
3006 vec![
3007 InstructionCode::GET_INTERNAL_SLOT.into(),
3008 0,
3010 0xff,
3011 0xff,
3012 0xff
3013 ]
3014 );
3015 }
3016
3017 #[test]
3019 fn deref() {
3020 let script = "*10u8";
3021 let (res, _) =
3022 compile_script(script, CompileOptions::default()).unwrap();
3023 assert_eq!(
3024 res,
3025 vec![
3026 InstructionCode::DEREF.into(),
3027 InstructionCode::UINT_8.into(),
3028 10,
3030 ]
3031 );
3032 }
3033
3034 #[test]
3035 fn type_literal_integer() {
3036 let script = "type<1>";
3037 let (res, _) =
3038 compile_script(script, CompileOptions::default()).unwrap();
3039 assert_eq!(
3040 res,
3041 vec![
3042 InstructionCode::TYPE_EXPRESSION.into(),
3043 TypeInstructionCode::TYPE_LITERAL_INTEGER.into(),
3044 2,
3046 1,
3047 0,
3048 0,
3049 0,
3050 1
3051 ]
3052 );
3053 }
3054
3055 #[test]
3056 fn type_core_type_integer() {
3057 let script = "integer";
3058 let (res, _) =
3059 compile_script(script, CompileOptions::default()).unwrap();
3060 let mut instructions: Vec<u8> =
3061 vec![InstructionCode::GET_INTERNAL_REF.into()];
3062 instructions.append(
3064 &mut PointerAddress::from(CoreLibPointerId::Integer(None))
3065 .bytes()
3066 .to_vec(),
3067 );
3068 assert_eq!(res, instructions);
3069 }
3070
3071 #[test]
3072 fn compile_continuous_terminated_script() {
3073 let input = vec!["1u8", "2u8", "3u8;"];
3074 let expected_output = vec![
3075 vec![
3076 InstructionCode::UNBOUNDED_STATEMENTS.into(),
3077 InstructionCode::UINT_8.into(),
3078 1,
3079 ],
3080 vec![InstructionCode::UINT_8.into(), 2],
3081 vec![
3082 InstructionCode::UINT_8.into(),
3083 3,
3084 InstructionCode::UNBOUNDED_STATEMENTS_END.into(),
3085 1, ],
3087 ];
3088
3089 assert_unbounded_input_matches_output(input, expected_output);
3090 }
3091
3092 #[test]
3093 fn compile_continuous_unterminated_script() {
3094 let input = vec!["1u8", "2u8 + 3u8", "3u8"];
3095 let expected_output = vec![
3096 vec![
3097 InstructionCode::UNBOUNDED_STATEMENTS.into(),
3098 InstructionCode::UINT_8.into(),
3099 1,
3100 ],
3101 vec![
3102 InstructionCode::ADD.into(),
3103 InstructionCode::UINT_8.into(),
3104 2,
3105 InstructionCode::UINT_8.into(),
3106 3,
3107 ],
3108 vec![
3109 InstructionCode::UINT_8.into(),
3110 3,
3111 InstructionCode::UNBOUNDED_STATEMENTS_END.into(),
3112 0, ],
3114 ];
3115
3116 assert_unbounded_input_matches_output(input, expected_output);
3117 }
3118
3119 #[test]
3120 fn compile_continuous_complex() {
3121 let input = vec!["1u8", "integer"];
3122 let expected_output = vec![
3123 vec![
3124 InstructionCode::UNBOUNDED_STATEMENTS.into(),
3125 InstructionCode::UINT_8.into(),
3126 1,
3127 ],
3128 vec![
3129 InstructionCode::GET_INTERNAL_REF.into(),
3130 100,
3132 0,
3133 0,
3134 InstructionCode::UNBOUNDED_STATEMENTS_END.into(),
3135 0, ],
3137 ];
3138
3139 assert_unbounded_input_matches_output(input, expected_output);
3140 }
3141
3142 #[test]
3143 fn test_get_property_text() {
3144 init_logger_debug();
3145 let datex_script = "'test'.example";
3146 let result = compile_and_log(datex_script);
3147 let expected = vec![
3148 InstructionCode::GET_PROPERTY_TEXT.into(),
3149 7, b'e',
3151 b'x',
3152 b'a',
3153 b'm',
3154 b'p',
3155 b'l',
3156 b'e',
3157 InstructionCode::SHORT_TEXT.into(),
3159 4, b't',
3161 b'e',
3162 b's',
3163 b't',
3164 ];
3165 assert_eq!(result, expected);
3166 }
3167
3168 #[test]
3169 fn test_get_property_text_quoted() {
3170 init_logger_debug();
3171 let datex_script = "'test'.'example'";
3172 let result = compile_and_log(datex_script);
3173 let expected = vec![
3174 InstructionCode::GET_PROPERTY_TEXT.into(),
3175 7, b'e',
3177 b'x',
3178 b'a',
3179 b'm',
3180 b'p',
3181 b'l',
3182 b'e',
3183 InstructionCode::SHORT_TEXT.into(),
3185 4, b't',
3187 b'e',
3188 b's',
3189 b't',
3190 ];
3191 assert_eq!(result, expected);
3192 }
3193
3194 #[test]
3195 fn test_get_property_index() {
3196 init_logger_debug();
3197 let datex_script = "'test'.42";
3198 let result = compile_and_log(datex_script);
3199 let expected = vec![
3200 InstructionCode::GET_PROPERTY_INDEX.into(),
3201 42,
3203 0,
3204 0,
3205 0,
3206 InstructionCode::SHORT_TEXT.into(),
3208 4, b't',
3210 b'e',
3211 b's',
3212 b't',
3213 ];
3214 assert_eq!(result, expected);
3215 }
3216
3217 #[test]
3218 fn test_get_property_dynamic() {
3219 init_logger_debug();
3220 let datex_script = "'test'.(1u8 + 2u8)";
3221 let result = compile_and_log(datex_script);
3222 let expected = vec![
3223 InstructionCode::GET_PROPERTY_DYNAMIC.into(),
3224 InstructionCode::ADD.into(),
3226 InstructionCode::UINT_8.into(),
3227 1,
3228 InstructionCode::UINT_8.into(),
3229 2,
3230 InstructionCode::SHORT_TEXT.into(),
3232 4, b't',
3234 b'e',
3235 b's',
3236 b't',
3237 ];
3238 assert_eq!(result, expected);
3239 }
3240
3241 #[test]
3242 fn test_set_property_text() {
3243 init_logger_debug();
3244 let datex_script = "'test'.example = 42u8";
3245 let result = compile_and_log(datex_script);
3246 let expected = vec![
3247 InstructionCode::SET_PROPERTY_TEXT.into(),
3248 7, b'e',
3250 b'x',
3251 b'a',
3252 b'm',
3253 b'p',
3254 b'l',
3255 b'e',
3256 InstructionCode::UINT_8.into(),
3258 42,
3259 InstructionCode::SHORT_TEXT.into(),
3261 4, b't',
3263 b'e',
3264 b's',
3265 b't',
3266 ];
3267 assert_eq!(result, expected);
3268 }
3269
3270 #[test]
3271 fn test_set_property_index() {
3272 init_logger_debug();
3273 let datex_script = "'test'.42 = 43u8";
3274 let result = compile_and_log(datex_script);
3275 let expected = vec![
3276 InstructionCode::SET_PROPERTY_INDEX.into(),
3277 42,
3279 0,
3280 0,
3281 0,
3282 InstructionCode::UINT_8.into(),
3284 43,
3285 InstructionCode::SHORT_TEXT.into(),
3287 4, b't',
3289 b'e',
3290 b's',
3291 b't',
3292 ];
3293 assert_eq!(result, expected);
3294 }
3295
3296 #[test]
3297 fn test_set_property_dynamic() {
3298 init_logger_debug();
3299 let datex_script = "'test'.(1u8 + 2u8) = 43u8";
3300 let result = compile_and_log(datex_script);
3301 let expected = vec![
3302 InstructionCode::SET_PROPERTY_DYNAMIC.into(),
3303 InstructionCode::ADD.into(),
3305 InstructionCode::UINT_8.into(),
3306 1,
3307 InstructionCode::UINT_8.into(),
3308 2,
3309 InstructionCode::UINT_8.into(),
3311 43,
3312 InstructionCode::SHORT_TEXT.into(),
3314 4, b't',
3316 b'e',
3317 b's',
3318 b't',
3319 ];
3320 assert_eq!(result, expected);
3321 }
3322
3323 #[test]
3324 fn test_apply_no_arguments() {
3325 init_logger_debug();
3326 let datex_script = "'test'()";
3327 let result = compile_and_log(datex_script);
3328 let expected = vec![
3329 InstructionCode::APPLY_ZERO.into(),
3330 InstructionCode::SHORT_TEXT.into(),
3332 4, b't',
3334 b'e',
3335 b's',
3336 b't',
3337 ];
3338 assert_eq!(result, expected);
3339 }
3340
3341 #[test]
3342 fn test_apply_one_argument() {
3343 init_logger_debug();
3344 let datex_script = "'test' 42u8";
3345 let result = compile_and_log(datex_script);
3346 let expected = vec![
3347 InstructionCode::APPLY_SINGLE.into(),
3348 InstructionCode::UINT_8.into(),
3350 42,
3351 InstructionCode::SHORT_TEXT.into(),
3353 4, b't',
3355 b'e',
3356 b's',
3357 b't',
3358 ];
3359 assert_eq!(result, expected);
3360 }
3361
3362 #[test]
3363 fn test_apply_multiple_arguments() {
3364 init_logger_debug();
3365 let datex_script = "'test'(1u8, 2u8, 3u8)";
3366 let result = compile_and_log(datex_script);
3367 let expected = vec![
3368 InstructionCode::APPLY.into(),
3369 3, 0,
3371 InstructionCode::UINT_8.into(),
3373 1,
3374 InstructionCode::UINT_8.into(),
3376 2,
3377 InstructionCode::UINT_8.into(),
3379 3,
3380 InstructionCode::SHORT_TEXT.into(),
3382 4, b't',
3384 b'e',
3385 b's',
3386 b't',
3387 ];
3388 assert_eq!(result, expected);
3389 }
3390}