customasm/expr/
expression.rs

1use crate::*;
2
3
4#[derive(Clone, Debug)]
5pub enum Expr
6{
7	Literal(diagn::Span, Value),
8	Variable(diagn::Span, String),
9	StructInit {
10		span: diagn::Span,
11		members_init: Vec<ExprStructMemberInit>,
12	},
13	NestingLevel {
14		span: diagn::Span,
15		nesting_level: usize,
16	},
17	MemberAccess {
18		span: diagn::Span,
19		lhs: Box<Expr>,
20		member_name: String,
21	},
22	UnaryOp(diagn::Span, diagn::Span, UnaryOp, Box<Expr>),
23	BinaryOp(diagn::Span, diagn::Span, BinaryOp, Box<Expr>, Box<Expr>),
24	TernaryOp(diagn::Span, Box<Expr>, Box<Expr>, Box<Expr>),
25	Slice(diagn::Span, diagn::Span, Box<Expr>, Box<Expr>, Box<Expr>),
26	SliceShort(diagn::Span, diagn::Span, Box<Expr>, Box<Expr>),
27	Block(diagn::Span, Vec<Expr>),
28	Call(diagn::Span, Box<Expr>, Vec<Expr>),
29	Asm(diagn::Span, asm::AstTopLevel),
30}
31
32
33#[derive(Clone, Debug)]
34pub struct ExprStructMemberInit
35{
36	pub span: diagn::Span,
37	pub name: String,
38	pub value: Expr,
39}
40
41
42#[derive(Clone, Debug)]
43pub enum Value
44{
45	Unknown(ValueMetadata),
46	FailedConstraint(ValueMetadata, diagn::Message),
47	Void(ValueMetadata),
48	Integer(ValueMetadata, util::BigInt),
49	String(ValueMetadata, ValueString),
50	Bool(ValueMetadata, bool),
51	Struct(ValueMetadata, ValueStruct),
52	ExprBuiltInFunction(ValueMetadata, String),
53	AsmBuiltInFunction(ValueMetadata, String),
54	Function(ValueMetadata, util::ItemRef<asm::Function>),
55	Bankdef(ValueMetadata, util::ItemRef<asm::Bankdef>),
56}
57
58
59#[derive(Clone, Debug)]
60pub struct ValueMetadata
61{
62	pub symbol_ref: Option<util::ItemRef<asm::Symbol>>,
63	pub bank_ref: Option<util::ItemRef<asm::Bankdef>>,
64}
65
66
67#[derive(Clone, Debug, PartialEq)]
68pub struct ValueString
69{
70	pub utf8_contents: String,
71	pub encoding: String,
72}
73
74
75#[derive(Clone, Debug, PartialEq)]
76pub struct ValueStruct
77{
78	pub members: Vec<ValueStructMember>,
79}
80
81
82#[derive(Clone, Debug, PartialEq)]
83pub struct ValueStructMember
84{
85	pub name: String,
86	pub value: Value,
87}
88
89
90#[derive(Copy, Clone, Debug, Eq, PartialEq)]
91pub enum UnaryOp
92{
93	Neg,
94	Not
95}
96
97
98#[derive(Copy, Clone, Debug, Eq, PartialEq)]
99pub enum BinaryOp
100{
101	Assign,
102	
103	Add, Sub, Mul, Div, Mod,
104	Shl, Shr,
105	And, Or, Xor,
106	
107	Eq, Ne,
108	Lt, Le,
109	Gt, Ge,
110	
111	LazyAnd, LazyOr,
112	
113	Concat
114}
115
116
117impl Expr
118{
119	pub fn new_dummy() -> Expr
120	{
121		Expr::Literal(diagn::Span::new_dummy(), Value::make_bool(false))
122	}
123
124	
125	pub fn span(&self) -> diagn::Span
126	{
127		match self
128		{
129			&Expr::Literal      (span, ..) => span,
130			&Expr::Variable     (span, ..) => span,
131			&Expr::StructInit   { span, .. } => span,
132			&Expr::NestingLevel { span, .. } => span,
133			&Expr::MemberAccess { span, .. } => span,
134			&Expr::UnaryOp      (span, ..) => span,
135			&Expr::BinaryOp     (span, ..) => span,
136			&Expr::TernaryOp    (span, ..) => span,
137			&Expr::Slice        (span, ..) => span,
138			&Expr::SliceShort   (span, ..) => span,
139			&Expr::Block        (span, ..) => span,
140			&Expr::Call         (span, ..) => span,
141			&Expr::Asm          (span, ..) => span,
142		}
143	}
144}
145
146
147impl Value
148{
149	pub fn type_name(&self) -> &str
150	{
151		match self
152		{
153			Value::Unknown(..) => "unknown",
154			Value::FailedConstraint(..) => "failed constraint",
155			Value::Void(..) => "void",
156			Value::Integer(..) => "integer",
157			Value::String(..) => "string",
158			Value::Bool(..) => "bool",
159			Value::Struct(..) => "struct",
160			Value::ExprBuiltInFunction(..) => "built-in function",
161			Value::AsmBuiltInFunction(..) => "built-in function",
162			Value::Function(..) => "function",
163			Value::Bankdef(..) => "bankdef",
164		}
165	}
166
167
168	pub fn is_unknown(&self) -> bool
169	{
170		match self
171		{
172			Value::Unknown(_) => true,
173			_ => false,
174		}
175	}
176
177
178	pub fn should_propagate(&self) -> bool
179	{
180		match self
181		{
182			Value::Unknown(_) => true,
183			Value::FailedConstraint(_, _) => true,
184			_ => false,
185		}
186	}
187
188	
189	pub fn make_literal(&self) -> Expr
190	{
191		Expr::Literal(diagn::Span::new_dummy(), self.clone())
192	}
193
194
195	pub fn make_unknown() -> Value
196	{
197		Value::Unknown(Value::make_metadata())
198	}
199
200
201	pub fn make_void() -> Value
202	{
203		Value::Void(Value::make_metadata())
204	}
205
206
207	pub fn make_integer<T: Into<util::BigInt>>(value: T) -> Value
208	{
209		Value::Integer(
210			Value::make_metadata(),
211			value.into())
212	}
213
214
215	pub fn make_maybe_integer<T: Into<util::BigInt>>(maybe_value: Option<T>) -> Value
216	{
217		if let Some(value) = maybe_value
218		{
219			Value::Integer(
220				Value::make_metadata(),
221				value.into())
222		}
223		else
224		{
225			Value::make_void()
226		}
227	}
228
229
230	pub fn make_bool(value: bool) -> Value
231	{
232		Value::Bool(
233			Value::make_metadata(),
234			value)
235	}
236
237
238	pub fn make_string<T: Into<String>, S: Into<String>>(value: T, encoding: S) -> Value
239	{
240		Value::String(
241			Value::make_metadata(),
242			ValueString {
243				utf8_contents: value.into(),
244				encoding: encoding.into(),
245			})
246	}
247
248
249	pub fn make_struct(value: ValueStruct) -> Value
250	{
251		Value::Struct(
252			Value::make_metadata(),
253			value)
254	}
255
256
257	pub fn make_bankdef(value: util::ItemRef<asm::Bankdef>) -> Value
258	{
259		Value::Bankdef(
260			Value::make_metadata(),
261			value)
262	}
263
264	
265	pub fn make_metadata() -> ValueMetadata
266	{
267		ValueMetadata {
268			symbol_ref: None,
269			bank_ref: None,
270		}
271	}
272
273
274	pub fn with_symbol_ref(mut self, symbol_ref: util::ItemRef<asm::Symbol>) -> Value
275	{
276		self.get_mut_metadata().symbol_ref = Some(symbol_ref);
277		self
278	}
279
280
281	pub fn with_bank_ref(mut self, bank_ref: util::ItemRef<asm::Bankdef>) -> Value
282	{
283		self.get_mut_metadata().bank_ref = Some(bank_ref);
284		self
285	}
286
287
288	pub fn get_metadata(&self) -> &ValueMetadata
289	{
290		match self
291		{
292			Value::Unknown(meta, ..) => meta,
293			Value::FailedConstraint(meta, ..) => meta,
294			Value::Void(meta, ..) => meta,
295			Value::Integer(meta, ..) => meta,
296			Value::String(meta, ..) => meta,
297			Value::Bool(meta, ..) => meta,
298			Value::Struct(meta, ..) => meta,
299			Value::ExprBuiltInFunction(meta, ..) => meta,
300			Value::AsmBuiltInFunction(meta, ..) => meta,
301			Value::Function(meta, ..) => meta,
302			Value::Bankdef(meta, ..) => meta,
303		}
304	}
305
306
307	pub fn get_mut_metadata(&mut self) -> &mut ValueMetadata
308	{
309		match self
310		{
311			Value::Unknown(meta, ..) => meta,
312			Value::FailedConstraint(meta, ..) => meta,
313			Value::Void(meta, ..) => meta,
314			Value::Integer(meta, ..) => meta,
315			Value::String(meta, ..) => meta,
316			Value::Bool(meta, ..) => meta,
317			Value::Struct(meta, ..) => meta,
318			Value::ExprBuiltInFunction(meta, ..) => meta,
319			Value::AsmBuiltInFunction(meta, ..) => meta,
320			Value::Function(meta, ..) => meta,
321			Value::Bankdef(meta, ..) => meta,
322		}
323	}
324
325
326	pub fn get_bigint(&self) -> Option<util::BigInt>
327	{
328		match &self
329		{
330			&Value::Integer(_, bigint) => Some(bigint.clone()),
331			&Value::String(_, s) => Some(s.to_bigint()),
332			_ => None,
333		}
334	}
335
336
337	pub fn coallesce_to_integer<'a>(
338		&'a self)
339		-> std::borrow::Cow<'a, expr::Value>
340	{
341		match self
342		{
343			Value::String(_, s) =>
344				std::borrow::Cow::Owned(
345					expr::Value::make_integer(s.to_bigint())),
346
347			_ => std::borrow::Cow::Borrowed(self),
348		}
349	}
350
351
352	pub fn unwrap_bigint(
353		&self)
354		-> &util::BigInt
355	{
356		match &self
357		{
358			Value::Integer(_, bigint) => bigint,
359			_ => panic!(),
360		}
361	}
362
363
364	pub fn expect_bigint(
365		&self,
366		report: &mut diagn::Report,
367		span: diagn::Span)
368		-> Result<&util::BigInt, ()>
369	{
370		match &self
371		{
372			Value::Integer(_, bigint) => Ok(bigint),
373
374			Value::Unknown(_) =>
375			{
376				report.error_span(
377					"value is unknown",
378					span);
379
380				Err(())
381			}
382
383			_ =>
384			{
385				report.error_span(
386					format!(
387						"expected integer, got {}",
388						self.type_name()),
389					span);
390
391				Err(())
392			}
393		}
394	}
395
396
397	pub fn expect_bigint_mut(
398		&mut self,
399		report: &mut diagn::Report,
400		span: diagn::Span)
401		-> Result<&mut util::BigInt, ()>
402	{
403		match self
404		{
405			Value::Integer(_, bigint) => Ok(bigint),
406
407			Value::Unknown(_) =>
408			{
409				report.error_span(
410					"value is unknown",
411					span);
412
413				Err(())
414			}
415
416			_ =>
417			{
418				report.error_span(
419					format!(
420						"expected integer, got {}",
421						self.type_name()),
422					span);
423
424				Err(())
425			}
426		}
427	}
428
429
430	pub fn expect_sized_bigint(
431		&self,
432		report: &mut diagn::Report,
433		span: diagn::Span)
434		-> Result<&util::BigInt, ()>
435	{
436		let bigint = self.expect_bigint(report, span)?;
437		
438		match bigint.size
439		{
440			Some(_) => Ok(&bigint),
441			
442			None =>
443			{
444				report.error_span(
445					format!(
446						"expected integer with definite size, got {}",
447						self.type_name()),
448					span);
449
450				Err(())
451			}
452		}
453	}
454
455
456	pub fn expect_sized_integerlike(
457		&self,
458		report: &mut diagn::Report,
459		span: diagn::Span)
460		-> Result<(util::BigInt, usize), ()>
461	{
462		if let Some(bigint) = self.coallesce_to_integer().get_bigint()
463		{
464			if let Some(size) = bigint.size
465			{
466				return Ok((bigint, size));
467			}
468
469			report.error_span(
470				"value has no definite size",
471				span);
472			
473			return Err(());
474		}
475
476		report.error_span(
477			format!(
478				"expected integer-like value with definite size, got {}",
479				self.type_name()),
480			span);
481
482		Err(())
483	}
484
485
486	pub fn expect_error_or_bigint(
487		self,
488		report: &mut diagn::Report,
489		span: diagn::Span)
490		-> Result<expr::Value, ()>
491	{
492		let coallesced = self.coallesce_to_integer();
493
494		match coallesced.as_ref()
495		{
496			expr::Value::Unknown(_) |
497			expr::Value::FailedConstraint(_, _) =>
498				Ok(coallesced.into_owned()),
499
500			expr::Value::Integer(_, _) =>
501				Ok(coallesced.into_owned()),
502
503			_ =>
504			{
505				report.error_span(
506					format!(
507						"expected integer, got {}",
508						coallesced.type_name()),
509					span);
510
511				Err(())
512			}
513		}
514	}
515
516
517	pub fn expect_error_or_sized_bigint(
518		self,
519		report: &mut diagn::Report,
520		span: diagn::Span)
521		-> Result<expr::Value, ()>
522	{
523		let coallesced = self.coallesce_to_integer();
524
525		match coallesced.as_ref()
526		{
527			expr::Value::Unknown(_) |
528			expr::Value::FailedConstraint(_, _) =>
529				Ok(coallesced.into_owned()),
530
531			expr::Value::Integer(_, bigint)
532				if bigint.size.is_some() =>
533				Ok(expr::Value::make_integer(bigint.to_owned())),
534
535			_ =>
536			{
537				report.error_span(
538					format!(
539						"expected integer with definite size, got {}",
540						coallesced.type_name()),
541					span);
542
543				Err(())
544			}
545		}
546	}
547
548
549	pub fn expect_error_or_bool(
550		self,
551		report: &mut diagn::Report,
552		span: diagn::Span)
553		-> Result<expr::Value, ()>
554	{
555		let coallesced = self.coallesce_to_integer();
556
557		match coallesced.as_ref()
558		{
559			expr::Value::Unknown(_) |
560			expr::Value::FailedConstraint(_, _) =>
561				Ok(coallesced.into_owned()),
562
563			expr::Value::Bool(_, _) =>
564				Ok(coallesced.into_owned()),
565
566			_ =>
567			{
568				report.error_span(
569					format!(
570						"expected boolean, got {}",
571						coallesced.type_name()),
572					span);
573
574				Err(())
575			}
576		}
577	}
578
579
580	pub fn as_usize(&self) -> Option<usize>
581	{
582		match &self
583		{
584			Value::Integer(_, bigint) =>
585				bigint.maybe_into::<usize>(),
586
587			_ => None,
588		}
589	}
590
591
592	pub fn expect_usize(
593		&self,
594		report: &mut diagn::Report,
595		span: diagn::Span)
596		-> Result<usize, ()>
597	{
598		match &self
599		{
600			Value::Integer(_, bigint) =>
601				bigint.checked_into::<usize>(
602					report,
603					span),
604
605			Value::Unknown(_) =>
606			{
607				report.error_span(
608					"value is unknown",
609					span);
610
611				Err(())
612			}
613
614			_ =>
615			{
616				report.error_span(
617					format!(
618						"expected non-negative integer, got {}",
619						self.type_name()),
620					span);
621
622				Err(())
623			}
624		}
625	}
626
627
628	pub fn expect_error_or_usize(
629		self,
630		report: &mut diagn::Report,
631		span: diagn::Span)
632		-> Result<expr::Value, ()>
633	{
634		match &self
635		{
636			expr::Value::Unknown(_) |
637			expr::Value::FailedConstraint(_, _) =>
638				Ok(self.clone()),
639				
640			expr::Value::Integer(_, bigint) =>
641			{
642				bigint.checked_into::<usize>(
643					report,
644					span)?;
645
646				Ok(self.clone())
647			}
648
649			_ =>
650			{
651				report.error_span(
652					format!(
653						"expected non-negative integer, got {}",
654						self.type_name()),
655					span);
656
657				Err(())
658			}
659		}
660	}
661
662
663	pub fn expect_nonzero_usize(
664		&self,
665		report: &mut diagn::Report,
666		span: diagn::Span)
667		-> Result<usize, ()>
668	{
669		match &self
670		{
671			Value::Integer(_, bigint) =>
672			{
673				bigint.checked_into_nonzero_usize(
674					report,
675					span)
676			}
677
678			Value::Unknown(_) =>
679			{
680				report.error_span(
681					"value is unknown",
682					span);
683
684				Err(())
685			}
686
687			_ =>
688			{
689				report.error_span(
690					format!(
691						"expected positive integer, got {}",
692						self.type_name()),
693					span);
694
695				Err(())
696			}
697		}
698	}
699
700
701	pub fn expect_bool(
702		&self,
703		report: &mut diagn::Report,
704		span: diagn::Span)
705		-> Result<bool, ()>
706	{
707		match &self
708		{
709			expr::Value::Bool(_, value) => Ok(*value),
710
711			_ =>
712			{
713				report.error_span(
714					format!(
715						"expected boolean, got {}",
716						self.type_name()),
717					span);
718
719				Err(())
720			}
721		}
722	}
723
724
725	pub fn expect_string(
726		&self,
727		report: &mut diagn::Report,
728		span: diagn::Span)
729		-> Result<&ValueString, ()>
730	{
731		match &self
732		{
733			expr::Value::String(_, value) => Ok(value),
734
735			_ =>
736			{
737				report.error_span(
738					format!(
739						"expected string, got {}",
740						self.type_name()),
741					span);
742
743				Err(())
744			}
745		}
746	}
747}
748
749
750impl std::cmp::PartialEq for Value
751{
752	fn eq(&self, other: &Value) -> bool
753	{
754		// Ignore the values' metadata in comparisons.
755		match self
756		{
757			Value::Unknown(_) => match other
758			{
759				Value::Unknown(_) => true,
760				_ => false,
761			}
762
763			Value::FailedConstraint(_, _) => match other
764			{
765				Value::FailedConstraint(_, _) => true,
766				_ => false,
767			}
768
769			Value::Void(_) => match other
770			{
771				Value::Void(_) => true,
772				_ => false,
773			}
774
775			Value::Integer(_, a) => match other
776			{
777				Value::Integer(_, b) => a == b,
778				_ => false,
779			}
780
781			Value::Bool(_, a) => match other
782			{
783				Value::Bool(_, b) => a == b,
784				_ => false,
785			}
786
787			Value::String(_, a) => match other
788			{
789				Value::String(_, b) => a == b,
790				_ => false,
791			}
792
793			Value::Struct(_, a) => match other
794			{
795				Value::Struct(_, b) => a == b,
796				_ => false,
797			}
798
799			Value::ExprBuiltInFunction(_, a) => match other
800			{
801				Value::ExprBuiltInFunction(_, b) => a == b,
802				_ => false,
803			}
804
805			Value::AsmBuiltInFunction(_, a) => match other
806			{
807				Value::AsmBuiltInFunction(_, b) => a == b,
808				_ => false,
809			}
810
811			Value::Function(_, a) => match other
812			{
813				Value::Function(_, b) => a == b,
814				_ => false,
815			}
816
817			Value::Bankdef(_, a) => match other
818			{
819				Value::Bankdef(_, b) => a == b,
820				_ => false,
821			}
822		}
823	}
824}
825
826
827impl ValueString
828{
829	pub fn to_bigint(&self) -> util::BigInt
830	{
831		match &*self.encoding
832		{
833			"utf8" => util::BigInt::from_bytes_be(&self.utf8_contents.as_bytes()),
834			"utf16be" =>
835			{
836				let units = self.utf8_contents.encode_utf16();
837				let mut bytes = Vec::new();
838				for unit in units
839				{
840					bytes.push(((unit >> 8) & 0xff) as u8);
841					bytes.push(((unit >> 0) & 0xff) as u8);
842				}
843					
844				util::BigInt::from_bytes_be(&bytes[..])
845			}
846			"utf16le" =>
847			{
848				let units = self.utf8_contents.encode_utf16();
849				let mut bytes = Vec::new();
850				for unit in units
851				{
852					bytes.push(((unit >> 0) & 0xff) as u8);
853					bytes.push(((unit >> 8) & 0xff) as u8);
854				}
855					
856				util::BigInt::from_bytes_be(&bytes[..])
857			}
858			"utf32be" =>
859			{
860				let units = self.utf8_contents.chars();
861				let mut bytes = Vec::new();
862				for unit in units
863				{
864					bytes.push(((unit as u32 >> 24) & 0xff) as u8);
865					bytes.push(((unit as u32 >> 16) & 0xff) as u8);
866					bytes.push(((unit as u32 >> 8) & 0xff) as u8);
867					bytes.push(((unit as u32 >> 0) & 0xff) as u8);
868				}
869					
870				util::BigInt::from_bytes_be(&bytes[..])
871			}
872			"utf32le" =>
873			{
874				let units = self.utf8_contents.chars();
875				let mut bytes = Vec::new();
876				for unit in units
877				{
878					bytes.push(((unit as u32 >> 0) & 0xff) as u8);
879					bytes.push(((unit as u32 >> 8) & 0xff) as u8);
880					bytes.push(((unit as u32 >> 16) & 0xff) as u8);
881					bytes.push(((unit as u32 >> 24) & 0xff) as u8);
882				}
883					
884				util::BigInt::from_bytes_be(&bytes[..])
885			}
886			"ascii" =>
887			{
888				let units = self.utf8_contents.chars();
889				let bytes = units.map(|c|
890				{
891					if c as u32 >= 0x100
892					{
893						0x00
894					}
895					else
896					{
897						c as u8
898					}
899				});
900					
901				util::BigInt::from_bytes_be(&bytes.collect::<Vec<_>>()[..])
902			}
903			_ => panic!("invalid string encoding"),
904		}
905	}
906}