From 6929a6091ed6487cd87379a8fca8096c0e1d4de2 2021-04-08 10:05:57 From: MH Date: 2021-04-08 10:05:57 Subject: [PATCH] start on binding expressions --- diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index c83e56ebea87ba49962e3dd391b176c69e08a00e..95cbc2805eee0963ce98b29bbbdb366651dce657 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -154,6 +154,7 @@ define_new_ast_id!(ExpressionStatementId, StatementId, index(ExpressionStatement define_aliased_ast_id!(ExpressionId, Id, index(Expression, expressions)); define_new_ast_id!(AssignmentExpressionId, ExpressionId, index(AssignmentExpression, Expression::Assignment, expressions), alloc(alloc_assignment_expression)); +define_new_ast_id!(BindingExpressionId, ExpressionId, index(BindingExpression, Expression::Binding, expressions), alloc(alloc_binding_expression)); define_new_ast_id!(ConditionalExpressionId, ExpressionId, index(ConditionalExpression, Expression::Conditional, expressions), alloc(alloc_conditional_expression)); define_new_ast_id!(BinaryExpressionId, ExpressionId, index(BinaryExpression, Expression::Binary, expressions), alloc(alloc_binary_expression)); define_new_ast_id!(UnaryExpressionId, ExpressionId, index(UnaryExpression, Expression::Unary, expressions), alloc(alloc_unary_expression)); @@ -1843,6 +1844,7 @@ pub enum ExpressionParent { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum Expression { Assignment(AssignmentExpression), + Binding(BindingExpression), Conditional(ConditionalExpression), Binary(BinaryExpression), Unary(UnaryExpression), @@ -1938,6 +1940,7 @@ impl Expression { pub fn parent(&self) -> &ExpressionParent { match self { Expression::Assignment(expr) => &expr.parent, + Expression::Binding(expr) => &expr.parent, Expression::Conditional(expr) => &expr.parent, Expression::Binary(expr) => &expr.parent, Expression::Unary(expr) => &expr.parent, @@ -1962,6 +1965,7 @@ impl Expression { pub fn set_parent(&mut self, parent: ExpressionParent) { match self { Expression::Assignment(expr) => expr.parent = parent, + Expression::Binding(expr) => expr.parent = parent, Expression::Conditional(expr) => expr.parent = parent, Expression::Binary(expr) => expr.parent = parent, Expression::Unary(expr) => expr.parent = parent, @@ -1977,6 +1981,7 @@ impl Expression { pub fn get_type(&self) -> &ConcreteType { match self { Expression::Assignment(expr) => &expr.concrete_type, + Expression::Binding(expr) => &expr.concrete_type, Expression::Conditional(expr) => &expr.concrete_type, Expression::Binary(expr) => &expr.concrete_type, Expression::Unary(expr) => &expr.concrete_type, @@ -1994,6 +1999,7 @@ impl Expression { pub fn get_type_mut(&mut self) -> &mut ConcreteType { match self { Expression::Assignment(expr) => &mut expr.concrete_type, + Expression::Binding(expr) => &mut expr.concrete_type, Expression::Conditional(expr) => &mut expr.concrete_type, Expression::Binary(expr) => &mut expr.concrete_type, Expression::Unary(expr) => &mut expr.concrete_type, @@ -2012,6 +2018,7 @@ impl SyntaxElement for Expression { fn position(&self) -> InputPosition { match self { Expression::Assignment(expr) => expr.position(), + Expression::Binding(expr) => expr.position, Expression::Conditional(expr) => expr.position(), Expression::Binary(expr) => expr.position(), Expression::Unary(expr) => expr.position(), @@ -2061,6 +2068,19 @@ impl SyntaxElement for AssignmentExpression { } } +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct BindingExpression { + pub this: BindingExpressionId, + // Phase 1: parser + pub position: InputPosition, + pub left: ExpressionId, + pub right: ExpressionId, + // Phase 2: linker + pub parent: ExpressionParent, + // Phase 3: type checking + pub concrete_type: ConcreteType, +} + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct ConditionalExpression { pub this: ConditionalExpressionId, diff --git a/src/protocol/ast_printer.rs b/src/protocol/ast_printer.rs index 4e56ceb4b25452f95d30e5868fcf1dc7daecbbd1..0818cfbac700900528d25955f2820909bcaa9307 100644 --- a/src/protocol/ast_printer.rs +++ b/src/protocol/ast_printer.rs @@ -41,6 +41,7 @@ const PREFIX_NEW_STMT_ID: &'static str = "SNew"; const PREFIX_PUT_STMT_ID: &'static str = "SPut"; const PREFIX_EXPR_STMT_ID: &'static str = "SExp"; const PREFIX_ASSIGNMENT_EXPR_ID: &'static str = "EAsi"; +const PREFIX_BINDING_EXPR_ID: &'static str = "EBnd"; const PREFIX_CONDITIONAL_EXPR_ID: &'static str = "ECnd"; const PREFIX_BINARY_EXPR_ID: &'static str = "EBin"; const PREFIX_UNARY_EXPR_ID: &'static str = "EUna"; @@ -594,6 +595,18 @@ impl ASTWriter { self.kv(indent2).with_s_key("ConcreteType") .with_custom_val(|v| write_concrete_type(v, heap, def_id, &expr.concrete_type)); }, + Expression::Binding(expr) => { + self.kv(indent).with_id(PREFIX_BINARY_EXPR_ID, expr.this.0.index) + .with_s_key("BindingExpr"); + self.kv(indent2).with_s_key("LeftExpression"); + self.write_expr(heap, expr.left, indent3); + self.kv(indent2).with_s_key("RightExpression"); + self.write_expr(heap, expr.right, indent3); + self.kv(indent2).with_s_key("Parent") + .with_custom_val(|v| write_expression_parent(v, &expr.parent)); + self.kv(indent2).with_s_key("ConcreteType") + .with_custom_val(|v| write_concrete_type(v, heap, def_id, &expr.concrete_type)); + }, Expression::Conditional(expr) => { self.kv(indent).with_id(PREFIX_CONDITIONAL_EXPR_ID, expr.this.0.index) .with_s_key("ConditionalExpr"); diff --git a/src/protocol/eval.rs b/src/protocol/eval.rs index 90f093995931cd3c1dab2a90d8b5fd96906a4eb7..dd398b4891def402aa7973b5e31997f4cde19e4b 100644 --- a/src/protocol/eval.rs +++ b/src/protocol/eval.rs @@ -1446,6 +1446,9 @@ impl Store { } Ok(value) } + Expression::Binding(expr) => { + unimplemented!("eval binding expression"); + } Expression::Conditional(expr) => { let test = self.eval(h, ctx, expr.test)?; if test.as_boolean().0 { diff --git a/src/protocol/lexer.rs b/src/protocol/lexer.rs index 29ed1c92942d206de98b701953917367d665bd00..899c94b56269f342729fbef52b089ce4fe8f8145 100644 --- a/src/protocol/lexer.rs +++ b/src/protocol/lexer.rs @@ -1261,6 +1261,19 @@ impl Lexer<'_> { } Ok(result) } + fn consume_binding_expression(&mut self, h: &mut Heap) -> Result { + if self.has_string("let") { + let position = self.source.pos(); + self.consume_whitespace(true)?; + let left_expr = self.consume_expression(h)?; + self.consume_whitespace(false)?; + self.consume_string(b"=")?; + self.consume_whitespace(false)?; + let right_expr = self.consume_expression(h)?; + } else { + self.consume_prefix_expression(h) + } + } fn consume_prefix_expression(&mut self, h: &mut Heap) -> Result { if self.has_string(b"+") || self.has_string(b"-") diff --git a/src/protocol/tests/parser_monomorphs.rs b/src/protocol/tests/parser_monomorphs.rs index 715a63ae4fa48b3e71c221aa7eb9ade2ebe4de4b..ed633531181e350ba4283c98d5897d0892dfbceb 100644 --- a/src/protocol/tests/parser_monomorphs.rs +++ b/src/protocol/tests/parser_monomorphs.rs @@ -91,9 +91,11 @@ fn test_union_monomorphs() { " union Result{ Ok(T), Err(E) } int instantiator() { + short a_short = 5; auto a = Result::Ok(0); auto b = Result::Ok(true); auto c = Result, Result>::Err(Result::Ok(5)); + auto d = Result, auto>::Err(Result::Ok(a_short)); return 0; } " @@ -103,5 +105,10 @@ fn test_union_monomorphs() { .assert_has_monomorph("bool;byte") .assert_has_monomorph("Result;Result") .assert_has_monomorph("short;long"); + }).for_function("instantiator", |f| { f + .for_variable("d", |v| { v + .assert_parser_type("auto") + .assert_concrete_type("Result,Result>"); + }); }); } \ No newline at end of file diff --git a/src/protocol/tests/parser_validation.rs b/src/protocol/tests/parser_validation.rs index 5af066d56fd571d4c2f7e67ed08978014f580150..483a57202bac2bf69144a6abe98d24bd0314a7a8 100644 --- a/src/protocol/tests/parser_validation.rs +++ b/src/protocol/tests/parser_validation.rs @@ -337,4 +337,18 @@ fn test_incorrect_union_instance() { ).error(|e| { e .assert_msg_has(0, "The variant 'A' of union 'Foo' expects 0"); }); + + Tester::new_single_source_expect_err( + "wrong embedded value", + " + union Foo{ A(int) } + Foo bar() { return Foo::A(false); } + " + ).error(|e| { e + .assert_occurs_at(0, "Foo::A") + .assert_msg_has(0, "Failed to fully resolve") + .assert_occurs_at(1, "false") + .assert_msg_has(1, "has been resolved to 'int'") + .assert_msg_has(1, "has been resolved to 'bool'"); + }); } \ No newline at end of file diff --git a/src/protocol/tests/utils.rs b/src/protocol/tests/utils.rs index 0804ded4884a70bad85a6a82ce985c884a4dd453..a2f6b37fba643e77166b334ae94a11a2a18eed41 100644 --- a/src/protocol/tests/utils.rs +++ b/src/protocol/tests/utils.rs @@ -622,6 +622,7 @@ impl<'a> VariableTester<'a> { } fn assert_postfix(&self) -> String { + println!("DEBUG: {:?}", self.assignment.concrete_type); format!( "Variable{{ name: {} }}", &String::from_utf8_lossy(&self.local.identifier.value) @@ -865,15 +866,13 @@ fn serialize_parser_type(buffer: &mut String, heap: &Heap, id: ParserTypeId) { } fn serialize_concrete_type(buffer: &mut String, heap: &Heap, def: DefinitionId, concrete: &ConcreteType) { - // Retrieve polymorphic variables, if present (since we're dealing with a - // concrete type we only expect procedure types) + // Retrieve polymorphic variables let poly_vars = match &heap[def] { Definition::Function(definition) => &definition.poly_vars, Definition::Component(definition) => &definition.poly_vars, Definition::Struct(definition) => &definition.poly_vars, Definition::Enum(definition) => &definition.poly_vars, Definition::Union(definition) => &definition.poly_vars, - _ => unreachable!("Error in testing utility: unexpected type for concrete type serialization"), }; fn serialize_recursive( @@ -897,24 +896,20 @@ fn serialize_concrete_type(buffer: &mut String, heap: &Heap, def: DefinitionId, CTP::Array => { idx = serialize_recursive(buffer, heap, poly_vars, concrete, idx + 1); buffer.push_str("[]"); - idx += 1; }, CTP::Slice => { idx = serialize_recursive(buffer, heap, poly_vars, concrete, idx + 1); buffer.push_str("[..]"); - idx += 1; }, CTP::Input => { buffer.push_str("in<"); idx = serialize_recursive(buffer, heap, poly_vars, concrete, idx + 1); buffer.push('>'); - idx += 1; }, CTP::Output => { buffer.push_str("out<"); idx = serialize_recursive(buffer, heap, poly_vars, concrete, idx + 1); buffer.push('>'); - idx += 1 }, CTP::Instance(definition_id, num_sub) => { let definition_name = heap[*definition_id].identifier(); @@ -927,7 +922,6 @@ fn serialize_concrete_type(buffer: &mut String, heap: &Heap, def: DefinitionId, } buffer.push('>'); } - idx += 1; } } @@ -992,6 +986,11 @@ fn seek_expr_in_expr bool>(heap: &Heap, start: ExpressionI .or_else(|| seek_expr_in_expr(heap, expr.left, f)) .or_else(|| seek_expr_in_expr(heap, expr.right, f)) }, + Expression::Binding(expr) => { + None + .or_else(|| seek_expr_in_expr(heap, expr.left, f)) + .or_else(|| seek_expr_in_expr(heap, expr.right, f)) + } Expression::Conditional(expr) => { None .or_else(|| seek_expr_in_expr(heap, expr.test, f))