diff --git a/src/compiler.rs b/src/compiler.rs index 98b6c3e..16d5311 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,7 +1,9 @@ use crate::errors::SourceError; -use crate::parser::{AstNode, Block, NodeId}; +use crate::parser::{AstNode, Block, Expr, NodeId}; use crate::protocol::Command; -use crate::resolver::{DeclId, Frame, NameBindings, ScopeId, VarId, Variable}; +use crate::resolver::{ + DeclId, Frame, NameBindings, ScopeId, TypeDecl, TypeDeclId, VarId, Variable, +}; use crate::typechecker::{TypeId, Types}; use std::collections::HashMap; @@ -57,8 +59,14 @@ pub struct Compiler { pub variables: Vec, /// Mapping of variable's name node -> Variable pub var_resolution: HashMap, - /// Declarations (commands, aliases, externs), indexed by VarId + /// Type declarations, indexed by TypeDeclId + pub type_decls: Vec, + /// Mapping of type decl's name node -> TypeDecl + pub type_resolution: HashMap, + /// Declarations (commands, aliases, externs), indexed by DeclId pub decls: Vec>, + /// Declaration NodeIds, indexed by DeclId + pub decl_nodes: Vec, /// Mapping of decl's name node -> Command pub decl_resolution: HashMap, @@ -94,7 +102,10 @@ impl Compiler { scope_stack: vec![], variables: vec![], var_resolution: HashMap::new(), + type_decls: vec![], + type_resolution: HashMap::new(), decls: vec![], + decl_nodes: vec![], decl_resolution: HashMap::new(), // variables: vec![], @@ -126,7 +137,9 @@ impl Compiler { if matches!( ast_node, - AstNode::Name | AstNode::Variable | AstNode::Int | AstNode::Float | AstNode::String + AstNode::Name + | AstNode::VarDecl + | AstNode::Expr(Expr::VarRef | Expr::Int | Expr::Float | Expr::String) ) { result.push_str(&format!( " \"{}\"", @@ -155,7 +168,10 @@ impl Compiler { self.scope_stack.extend(name_bindings.scope_stack); self.variables.extend(name_bindings.variables); self.var_resolution.extend(name_bindings.var_resolution); + self.type_decls.extend(name_bindings.type_decls); + self.type_resolution.extend(name_bindings.type_resolution); self.decls.extend(name_bindings.decls); + self.decl_nodes.extend(name_bindings.decl_nodes); self.decl_resolution.extend(name_bindings.decl_resolution); self.errors.extend(name_bindings.errors); } diff --git a/src/ir_generator.rs b/src/ir_generator.rs index 74a61f4..f2c91cc 100644 --- a/src/ir_generator.rs +++ b/src/ir_generator.rs @@ -1,6 +1,6 @@ use crate::compiler::Compiler; use crate::errors::{Severity, SourceError}; -use crate::parser::{AstNode, NodeId}; +use crate::parser::{AstNode, Expr, NodeId}; use nu_protocol::ast::{Math, Operator}; use nu_protocol::ir::{Instruction, IrBlock, Literal}; use nu_protocol::{RegId, Span}; @@ -97,7 +97,7 @@ impl<'a> IrGenerator<'a> { fn generate_node(&mut self, node_id: NodeId) -> Option { let ast_node = &self.compiler.ast_nodes[node_id.0]; match ast_node { - AstNode::Int => { + AstNode::Expr(Expr::Int) => { let next_reg = self.next_register(); let val = self.compiler.node_as_i64(node_id); self.add_instruction( @@ -109,7 +109,7 @@ impl<'a> IrGenerator<'a> { ); Some(next_reg) } - AstNode::Block(block_id) => { + AstNode::Expr(Expr::Block(block_id)) => { let block = &self.compiler.blocks[block_id.0]; let mut last = None; for id in &block.nodes { @@ -118,7 +118,7 @@ impl<'a> IrGenerator<'a> { } last } - AstNode::BinaryOp { lhs, op, rhs } => { + AstNode::Expr(Expr::BinaryOp { lhs, op, rhs }) => { let l = self.generate_node(*lhs)?; let r = self.generate_node(*rhs)?; let o = self.node_to_operator(*op)?; diff --git a/src/parser.rs b/src/parser.rs index c7b018a..d9bed64 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -54,25 +54,25 @@ pub enum BarewordContext { Call, } -// TODO: All nodes with Vec<...> should be moved to their own ID (like BlockId) to allow Copy trait #[derive(Debug, PartialEq, Clone)] -pub enum AstNode { - Int, - Float, - String, - Name, - Type { +pub enum TypeAst { + Ref { name: NodeId, args: Option, optional: bool, }, - TypeArgs(Vec), - RecordType { + Record { /// Contains [AstNode::Params] fields: NodeId, optional: bool, }, - Variable, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Expr { + Int, + Float, + String, // Booleans True, @@ -81,6 +81,106 @@ pub enum AstNode { // Empty values Null, + VarRef, + + Closure { + params: Option, + block: NodeId, + }, + + Call { + parts: Vec, + }, + NamedValue { + name: NodeId, + value: NodeId, + }, + BinaryOp { + lhs: NodeId, + op: NodeId, + rhs: NodeId, + }, + Range { + lhs: NodeId, + rhs: NodeId, + }, + List(Vec), + Table { + header: NodeId, + rows: Vec, + }, + Record { + pairs: Vec<(NodeId, NodeId)>, + }, + MemberAccess { + target: NodeId, + field: NodeId, + }, + Block(BlockId), + If { + condition: NodeId, + then_block: NodeId, + else_block: Option, + }, + Match { + target: NodeId, + match_arms: Vec<(NodeId, NodeId)>, + }, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Stmt { + // Definitions + Def { + name: NodeId, + type_params: Option, + params: NodeId, + in_out_types: Option, + block: NodeId, + }, + Alias { + new_name: NodeId, + old_name: NodeId, + }, + Let { + variable_name: NodeId, + ty: Option, + initializer: NodeId, + is_mutable: bool, + }, + + While { + condition: NodeId, + block: NodeId, + }, + For { + variable: NodeId, + range: NodeId, + block: NodeId, + }, + Loop { + block: NodeId, + }, + Return(Option), + Break, + Continue, + + Expr(NodeId), +} + +// TODO: All nodes with Vec<...> should be moved to their own ID (like BlockId) to allow Copy trait +#[derive(Debug, PartialEq, Clone)] +pub enum AstNode { + Expr(Expr), + Stmt(Stmt), + Type(TypeAst), + + Name, + /// For now, each type parameter is a Name + TypeParams(Vec), + TypeArgs(Vec), + VarDecl, + // Operators Pow, Multiply, @@ -111,36 +211,6 @@ pub enum AstNode { DivideAssignment, AppendAssignment, - // Statements - Let { - variable_name: NodeId, - ty: Option, - initializer: NodeId, - is_mutable: bool, - }, - While { - condition: NodeId, - block: NodeId, - }, - For { - variable: NodeId, - range: NodeId, - block: NodeId, - }, - Loop { - block: NodeId, - }, - Return(Option), - Break, - Continue, - - // Definitions - Def { - name: NodeId, - params: NodeId, - in_out_types: Option, - block: NodeId, - }, Params(Vec), Param { name: NodeId, @@ -149,14 +219,6 @@ pub enum AstNode { InOutTypes(Vec), /// Input/output type pair for a command InOutType(NodeId, NodeId), - Closure { - params: Option, - block: NodeId, - }, - Alias { - new_name: NodeId, - old_name: NodeId, - }, /// Long flag ('--' + one or more letters) FlagLong, @@ -165,46 +227,6 @@ pub enum AstNode { /// Group of short flags ('-' + more than 1 letters) FlagShortGroup, - // Expressions - Call { - parts: Vec, - }, - NamedValue { - name: NodeId, - value: NodeId, - }, - BinaryOp { - lhs: NodeId, - op: NodeId, - rhs: NodeId, - }, - Range { - lhs: NodeId, - rhs: NodeId, - }, - List(Vec), - Table { - header: NodeId, - rows: Vec, - }, - Record { - pairs: Vec<(NodeId, NodeId)>, - }, - MemberAccess { - target: NodeId, - field: NodeId, - }, - Block(BlockId), - If { - condition: NodeId, - then_block: NodeId, - else_block: Option, - }, - Match { - target: NodeId, - match_arms: Vec<(NodeId, NodeId)>, - }, - Statement(NodeId), Garbage, } @@ -300,8 +322,8 @@ impl Parser { let rhs = self.expression(); let span_end = self.get_span_end(rhs); - return self.create_node( - AstNode::BinaryOp { + return self.create_expr( + Expr::BinaryOp { lhs: leftmost, op, rhs, @@ -352,8 +374,8 @@ impl Parser { let lhs = expr_stack.last_mut().map_or(&mut leftmost, |l| &mut l.1); let (span_start, span_end) = self.spanning(*lhs, rhs); - *lhs = self.create_node( - AstNode::BinaryOp { lhs: *lhs, op, rhs }, + *lhs = self.create_expr( + Expr::BinaryOp { lhs: *lhs, op, rhs }, span_start, span_end, ); @@ -372,11 +394,7 @@ impl Parser { let (span_start, span_end) = self.spanning(*lhs, rhs); - *lhs = self.create_node( - AstNode::BinaryOp { lhs: *lhs, op, rhs }, - span_start, - span_end, - ); + *lhs = self.create_expr(Expr::BinaryOp { lhs: *lhs, op, rhs }, span_start, span_end); } leftmost @@ -407,19 +425,19 @@ impl Parser { } } Token::LSquare => self.list_or_table(), - Token::Int => self.advance_node(AstNode::Int, span), - Token::Float => self.advance_node(AstNode::Float, span), - Token::DoubleQuotedString => self.advance_node(AstNode::String, span), - Token::SingleQuotedString => self.advance_node(AstNode::String, span), + Token::Int => self.advance_node(AstNode::Expr(Expr::Int), span), + Token::Float => self.advance_node(AstNode::Expr(Expr::Float), span), + Token::DoubleQuotedString => self.advance_node(AstNode::Expr(Expr::String), span), + Token::SingleQuotedString => self.advance_node(AstNode::Expr(Expr::String), span), Token::Dollar => self.variable(), Token::Bareword => match self.compiler.get_span_contents_manual(span.start, span.end) { - b"true" => self.advance_node(AstNode::True, span), - b"false" => self.advance_node(AstNode::False, span), - b"null" => self.advance_node(AstNode::Null, span), + b"true" => self.advance_node(AstNode::Expr(Expr::True), span), + b"false" => self.advance_node(AstNode::Expr(Expr::False), span), + b"null" => self.advance_node(AstNode::Expr(Expr::Null), span), _ => match bareword_context { BarewordContext::String => { let node_id = self.name(); - self.compiler.ast_nodes[node_id.0] = AstNode::String; + self.compiler.ast_nodes[node_id.0] = AstNode::Expr(Expr::String); node_id } BarewordContext::Call => self.call(), @@ -445,8 +463,7 @@ impl Parser { let rhs = self.simple_expression(BarewordContext::String); let span_end = self.get_span_end(rhs); - expr = - self.create_node(AstNode::Range { lhs: expr, rhs }, span_start, span_end); + expr = self.create_expr(Expr::Range { lhs: expr, rhs }, span_start, span_end); } } else if self.is_dot() { // Member access @@ -467,9 +484,9 @@ impl Parser { let span_end = self.get_span_end(field_or_call); match self.compiler.get_node_mut(field_or_call) { - AstNode::Variable | AstNode::Name => { - expr = self.create_node( - AstNode::MemberAccess { + AstNode::Expr(Expr::VarRef) | AstNode::Name => { + expr = self.create_expr( + Expr::MemberAccess { target: expr, field: field_or_call, }, @@ -492,6 +509,7 @@ impl Parser { self.create_node(node, span.start, span.end) } + /// A variable name (reference, not declaration) pub fn variable(&mut self) -> NodeId { if self.is_dollar() { let span_start = self.position(); @@ -499,7 +517,7 @@ impl Parser { if let (Token::Bareword, name_span) = self.tokens.peek() { self.tokens.advance(); - self.create_node(AstNode::Variable, span_start, name_span.end) + self.create_expr(Expr::VarRef, span_start, name_span.end) } else { self.error("variable name must be a bareword") } @@ -508,6 +526,7 @@ impl Parser { } } + /// A variable name (declaration, not reference) pub fn variable_decl(&mut self) -> NodeId { let _span = span!(); @@ -519,7 +538,7 @@ impl Parser { if let (Token::Bareword, name_span) = self.tokens.peek() { self.tokens.advance(); - self.create_node(AstNode::Variable, span_start, name_span.end) + self.create_node(AstNode::VarDecl, span_start, name_span.end) } else { self.error("variable assignment name must be a bareword") } @@ -550,7 +569,7 @@ impl Parser { let span_end = self.position(); - self.create_node(AstNode::Call { parts }, span_start, span_end) + self.create_expr(Expr::Call { parts }, span_start, span_end) } pub fn list_or_table(&mut self) -> NodeId { @@ -573,7 +592,10 @@ impl Parser { } else if self.is_semicolon() { if items.len() != 1 { self.error("semicolon to create table should immediately follow headers"); - } else if !matches!(self.compiler.get_node(items[0]), AstNode::List(_)) { + } else if !matches!( + self.compiler.get_node(items[0]), + AstNode::Expr(Expr::List(_)) + ) { self.error_on_node("tables require a list for their headers", items[0]) } self.tokens.advance(); @@ -591,8 +613,8 @@ impl Parser { if is_table { let header = items.remove(0); - self.create_node( - AstNode::Table { + self.create_expr( + Expr::Table { header, rows: items, }, @@ -600,7 +622,7 @@ impl Parser { span_end, ) } else { - self.create_node(AstNode::List(items), span_start, span_end) + self.create_expr(Expr::List(items), span_start, span_end) } } @@ -624,7 +646,7 @@ impl Parser { self.rcurly(); span_end = self.position(); - return self.create_node(AstNode::Closure { params, block }, span_start, span_end); + return self.create_expr(Expr::Closure { params, block }, span_start, span_end); } let rollback_point = self.get_rollback_point(); @@ -663,8 +685,8 @@ impl Parser { span_end = self.position(); - self.create_node( - AstNode::Closure { + self.create_expr( + Expr::Closure { params: None, block, }, @@ -672,7 +694,7 @@ impl Parser { span_end, ) } else { - self.create_node(AstNode::Record { pairs: items }, span_start, span_end) + self.create_expr(Expr::Record { pairs: items }, span_start, span_end) } } @@ -729,8 +751,12 @@ impl Parser { pub fn string(&mut self) -> NodeId { match self.tokens.peek() { - (Token::DoubleQuotedString, span) => self.advance_node(AstNode::String, span), - (Token::SingleQuotedString, span) => self.advance_node(AstNode::String, span), + (Token::DoubleQuotedString, span) => { + self.advance_node(AstNode::Expr(Expr::String), span) + } + (Token::SingleQuotedString, span) => { + self.advance_node(AstNode::Expr(Expr::String), span) + } _ => self.error("expected: string"), } } @@ -812,7 +838,7 @@ impl Parser { } } - self.create_node(AstNode::Match { target, match_arms }, span_start, span_end) + self.create_expr(Expr::Match { target, match_arms }, span_start, span_end) } pub fn if_expression(&mut self) -> NodeId { @@ -846,8 +872,8 @@ impl Parser { None }; - self.create_node( - AstNode::If { + self.create_expr( + Expr::If { condition, then_block, else_block, @@ -935,6 +961,32 @@ impl Parser { self.create_node(AstNode::Params(param_list), span_start, span_end) } + pub fn type_params(&mut self) -> NodeId { + let _span = span!(); + let span_start = self.position(); + self.less_than(); + + let mut param_list = vec![]; + + while self.has_tokens() { + if self.is_greater_than() { + break; + } + + if self.is_comma() { + self.tokens.advance(); + continue; + } + + param_list.push(self.name()); + } + + let span_end = self.position() + 1; + self.greater_than(); + + self.create_node(AstNode::TypeParams(param_list), span_start, span_end) + } + pub fn type_args(&mut self) -> NodeId { let _span = span!(); let span_start = self.position(); @@ -983,7 +1035,7 @@ impl Parser { }; let span_end = self.position(); return self.create_node( - AstNode::RecordType { fields, optional }, + AstNode::Type(TypeAst::Record { fields, optional }), span.start, span_end, ); @@ -1003,11 +1055,11 @@ impl Parser { false }; self.create_node( - AstNode::Type { + AstNode::Type(TypeAst::Ref { name, args, optional, - }, + }), span.start, span.end, // FIXME: this uses the end of the name as its end ) @@ -1071,11 +1123,17 @@ impl Parser { let name = match self.tokens.peek() { (Token::Bareword, span) => self.advance_node(AstNode::Name, span), (Token::DoubleQuotedString | Token::SingleQuotedString, span) => { - self.advance_node(AstNode::String, span) + self.advance_node(AstNode::Expr(Expr::String), span) } _ => return self.error("expected def name"), }; + let type_params = if self.is_less_than() { + Some(self.type_params()) + } else { + None + }; + let params = self.signature_params(ParamsContext::Squares); let in_out_types = if self.is_colon() { Some(self.in_out_types()) @@ -1086,9 +1144,10 @@ impl Parser { let span_end = self.get_span_end(block); - self.create_node( - AstNode::Def { + self.create_stmt( + Stmt::Def { name, + type_params, params, in_out_types, block, @@ -1123,8 +1182,8 @@ impl Parser { let span_end = self.get_span_end(initializer); - self.create_node( - AstNode::Let { + self.create_stmt( + Stmt::Let { variable_name, ty, initializer, @@ -1160,8 +1219,8 @@ impl Parser { let span_end = self.get_span_end(initializer); - self.create_node( - AstNode::Let { + self.create_stmt( + Stmt::Let { variable_name, ty, initializer, @@ -1231,8 +1290,8 @@ impl Parser { if self.is_semicolon() { // This is a statement, not an expression self.tokens.advance(); - code_body.push(self.create_node( - AstNode::Statement(expression), + code_body.push(self.create_stmt( + Stmt::Expr(expression), exp_span_start, exp_span_end, )) @@ -1245,8 +1304,8 @@ impl Parser { self.compiler.blocks.push(Block::new(code_body)); let span_end = self.position(); - self.create_node( - AstNode::Block(BlockId(self.compiler.blocks.len() - 1)), + self.create_expr( + Expr::Block(BlockId(self.compiler.blocks.len() - 1)), span_start, span_end, ) @@ -1267,7 +1326,7 @@ impl Parser { let block = self.block(BlockContext::Curlies); let span_end = self.get_span_end(block); - self.create_node(AstNode::While { condition, block }, span_start, span_end) + self.create_stmt(Stmt::While { condition, block }, span_start, span_end) } pub fn for_statement(&mut self) -> NodeId { @@ -1282,8 +1341,8 @@ impl Parser { let block = self.block(BlockContext::Curlies); let span_end = self.get_span_end(block); - self.create_node( - AstNode::For { + self.create_stmt( + Stmt::For { variable, range, block, @@ -1300,7 +1359,7 @@ impl Parser { let block = self.block(BlockContext::Curlies); let span_end = self.get_span_end(block); - self.create_node(AstNode::Loop { block }, span_start, span_end) + self.create_stmt(Stmt::Loop { block }, span_start, span_end) } pub fn return_statement(&mut self) -> NodeId { @@ -1319,7 +1378,7 @@ impl Parser { None }; - self.create_node(AstNode::Return(ret_val), span_start, span_end) + self.create_stmt(Stmt::Return(ret_val), span_start, span_end) } pub fn continue_statement(&mut self) -> NodeId { @@ -1328,7 +1387,7 @@ impl Parser { self.keyword(b"continue"); let span_end = span_start + b"continue".len(); - self.create_node(AstNode::Continue, span_start, span_end) + self.create_stmt(Stmt::Continue, span_start, span_end) } pub fn break_statement(&mut self) -> NodeId { @@ -1337,7 +1396,7 @@ impl Parser { self.keyword(b"break"); let span_end = span_start + b"break".len(); - self.create_node(AstNode::Break, span_start, span_end) + self.create_stmt(Stmt::Break, span_start, span_end) } pub fn alias_statement(&mut self) -> NodeId { @@ -1356,7 +1415,7 @@ impl Parser { self.name() }; let span_end = self.get_span_end(old_name); - self.create_node(AstNode::Alias { new_name, old_name }, span_start, span_end) + self.create_stmt(Stmt::Alias { new_name, old_name }, span_start, span_end) } pub fn is_operator(&mut self) -> bool { @@ -1563,6 +1622,14 @@ impl Parser { node_id } + pub fn create_expr(&mut self, expr: Expr, span_start: usize, span_end: usize) -> NodeId { + self.create_node(AstNode::Expr(expr), span_start, span_end) + } + + pub fn create_stmt(&mut self, stmt: Stmt, span_start: usize, span_end: usize) -> NodeId { + self.create_node(AstNode::Stmt(stmt), span_start, span_end) + } + pub fn create_node(&mut self, ast_node: AstNode, span_start: usize, span_end: usize) -> NodeId { self.compiler.spans.push(Span { start: span_start, diff --git a/src/resolver.rs b/src/resolver.rs index bbdb7ca..3dc4d93 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -1,3 +1,4 @@ +use crate::parser::{Expr, Stmt, TypeAst}; use crate::protocol::{Command, Declaration}; use crate::{ compiler::Compiler, @@ -23,6 +24,7 @@ pub enum FrameType { pub struct Frame { pub frame_type: FrameType, pub variables: HashMap, NodeId>, + pub type_decls: HashMap, NodeId>, pub decls: HashMap, NodeId>, /// Node that defined the scope frame (e.g., a block or overlay) pub node_id: NodeId, @@ -33,6 +35,7 @@ impl Frame { Frame { frame_type: scope_type, variables: HashMap::new(), + type_decls: HashMap::new(), decls: HashMap::new(), node_id, } @@ -47,6 +50,15 @@ pub struct Variable { #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub struct VarId(pub usize); +#[derive(Debug, Clone)] +pub enum TypeDecl { + /// A type parameter. Holds the parameter name node + Param(NodeId), +} + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub struct TypeDeclId(pub usize); + #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub struct DeclId(pub usize); @@ -56,7 +68,10 @@ pub struct NameBindings { pub scope_stack: Vec, pub variables: Vec, pub var_resolution: HashMap, + pub type_decls: Vec, + pub type_resolution: HashMap, pub decls: Vec>, + pub decl_nodes: Vec, pub decl_resolution: HashMap, pub errors: Vec, } @@ -68,7 +83,10 @@ impl NameBindings { scope_stack: vec![], variables: vec![], var_resolution: HashMap::new(), + type_decls: vec![], + type_resolution: HashMap::new(), decls: vec![], + decl_nodes: vec![], decl_resolution: HashMap::new(), errors: vec![], } @@ -93,8 +111,14 @@ pub struct Resolver<'a> { pub variables: Vec, /// Mapping of variable's name node -> Variable pub var_resolution: HashMap, + /// Type declarations, indexed by TypeDeclId + pub type_decls: Vec, + /// Mapping of type decl's name node -> TypeDecl + pub type_resolution: HashMap, /// Declarations (commands, aliases, etc.), indexed by DeclId pub decls: Vec>, + /// Declaration NodeIds, indexed by DeclId + pub decl_nodes: Vec, /// Mapping of decl's name node -> Command pub decl_resolution: HashMap, /// Errors encountered during name binding @@ -109,7 +133,10 @@ impl<'a> Resolver<'a> { scope_stack: vec![], variables: vec![], var_resolution: HashMap::new(), + type_decls: vec![], + type_resolution: HashMap::new(), decls: vec![], + decl_nodes: vec![], decl_resolution: HashMap::new(), errors: vec![], } @@ -121,7 +148,10 @@ impl<'a> Resolver<'a> { scope_stack: self.scope_stack, variables: self.variables, var_resolution: self.var_resolution, + type_decls: self.type_decls, + type_resolution: self.type_resolution, decls: self.decls, + decl_nodes: self.decl_nodes, decl_resolution: self.decl_resolution, errors: self.errors, } @@ -149,13 +179,19 @@ impl<'a> Resolver<'a> { .map(|(name, id)| format!("{0}: {id:?}", String::from_utf8_lossy(name))) .collect(); + let mut types: Vec = scope + .type_decls + .iter() + .map(|(name, id)| format!("{0}: {id:?}", String::from_utf8_lossy(name))) + .collect(); + let mut decls: Vec = scope .decls .iter() .map(|(name, id)| format!("{0}: {id:?}", String::from_utf8_lossy(name))) .collect(); - if vars.is_empty() && decls.is_empty() { + if vars.is_empty() && types.is_empty() && decls.is_empty() { result.push_str(" (empty)\n"); continue; } @@ -168,6 +204,12 @@ impl<'a> Resolver<'a> { result.push_str(&line_var); } + if !types.is_empty() { + types.sort(); + let line_type = format!(" type decls: [ {0} ]\n", types.join(", ")); + result.push_str(&line_type); + } + if !decls.is_empty() { decls.sort(); let line_decl = format!(" decls: [ {0} ]\n", decls.join(", ")); @@ -199,10 +241,64 @@ impl<'a> Resolver<'a> { pub fn resolve_node(&mut self, node_id: NodeId) { // TODO: Move node_id param to the end, same as in typechecker match self.compiler.ast_nodes[node_id.0] { - AstNode::Variable => self.resolve_variable(node_id), - AstNode::Call { ref parts } => self.resolve_call(node_id, parts), - AstNode::Block(block_id) => self.resolve_block(node_id, block_id, None), - AstNode::Closure { params, block } => { + AstNode::Expr(ref expr) => self.resolve_expr(expr.clone(), node_id), + AstNode::Stmt(ref stmt) => self.resolve_stmt(stmt.clone(), node_id), + AstNode::Params(ref params) => { + for param in params { + if let AstNode::Param { name, ty } = self.compiler.ast_nodes[param.0] { + self.define_variable(name, false); + if let Some(ty) = ty { + self.resolve_node(ty); + } + } else { + panic!("param is not a param"); + } + } + } + AstNode::Type(ref ty) => match ty { + TypeAst::Ref { name, args, .. } => { + self.resolve_type(*name); + if let Some(args) = args { + self.resolve_node(*args); + } + } + TypeAst::Record { fields, .. } => { + let AstNode::Params(fields) = self.compiler.get_node(*fields) else { + panic!("Internal error: expected params for record field types"); + }; + for field in fields { + if let AstNode::Param { ty: Some(ty), .. } = self.compiler.get_node(*field) + { + self.resolve_node(*ty); + } + } + } + }, + AstNode::TypeArgs(ref args) => { + for arg in args { + self.resolve_node(*arg); + } + } + AstNode::InOutTypes(ref in_out_types) => { + for in_out_ty in in_out_types { + self.resolve_node(*in_out_ty); + } + } + AstNode::InOutType(in_ty, out_ty) => { + self.resolve_node(in_ty); + self.resolve_node(out_ty); + } + // All remaining matches do not contain NodeId => there is nothing to resolve + _ => (), + } + } + + pub fn resolve_expr(&mut self, expr: Expr, node_id: NodeId) { + match expr { + Expr::VarRef => self.resolve_variable(node_id), + Expr::Call { ref parts } => self.resolve_call(node_id, parts), + Expr::Block(block_id) => self.resolve_block(node_id, block_id, None), + Expr::Closure { params, block } => { // making sure the closure parameters and body end up in the same scope frame let closure_scope = if let Some(params) = params { self.enter_scope(block); @@ -212,61 +308,127 @@ impl<'a> Resolver<'a> { None }; - let AstNode::Block(block_id) = self.compiler.ast_nodes[block.0] else { + let AstNode::Expr(Expr::Block(block_id)) = self.compiler.ast_nodes[block.0] else { panic!("internal error: closure's body is not a block"); }; self.resolve_block(block, block_id, closure_scope); } - AstNode::Def { + Expr::BinaryOp { lhs, op: _, rhs } => { + self.resolve_node(lhs); + self.resolve_node(rhs); + } + Expr::Range { lhs, rhs } => { + self.resolve_node(lhs); + self.resolve_node(rhs); + } + Expr::List(ref nodes) => { + for node in nodes { + self.resolve_node(*node); + } + } + Expr::Table { header, ref rows } => { + self.resolve_node(header); + for row in rows { + self.resolve_node(*row); + } + } + Expr::Record { ref pairs } => { + for (key, val) in pairs { + self.resolve_node(*key); + self.resolve_node(*val); + } + } + Expr::MemberAccess { target, field } => { + self.resolve_node(target); + self.resolve_node(field); + } + Expr::If { + condition, + then_block, + else_block, + } => { + self.resolve_node(condition); + self.resolve_node(then_block); + if let Some(block) = else_block { + self.resolve_node(block); + } + } + Expr::Match { + target, + ref match_arms, + } => { + self.resolve_node(target); + for (arm_lhs, arm_rhs) in match_arms { + self.resolve_node(*arm_lhs); + self.resolve_node(*arm_rhs); + } + } + Expr::NamedValue { .. } => (/* seems unused for now */), + Expr::Int | Expr::Float | Expr::String | Expr::True | Expr::False | Expr::Null => {} + } + } + + pub fn resolve_stmt(&mut self, stmt: Stmt, node_id: NodeId) { + match stmt { + Stmt::Def { name, + type_params, params, - in_out_types: _, + in_out_types, block, } => { // define the command before the block to enable recursive calls - self.define_decl(name); + self.define_decl(name, node_id); // making sure the def parameters and body end up in the same scope frame self.enter_scope(block); + + if let Some(type_params) = type_params { + let AstNode::TypeParams(type_params) = self.compiler.get_node(type_params) + else { + panic!("Internal error: expected type params") + }; + for type_param_id in type_params { + self.define_type_decl(*type_param_id, TypeDecl::Param(*type_param_id)); + } + } + self.resolve_node(params); + if let Some(in_out_types) = in_out_types { + self.resolve_node(in_out_types); + } let def_scope = self.exit_scope(); - let AstNode::Block(block_id) = self.compiler.ast_nodes[block.0] else { + let AstNode::Expr(Expr::Block(block_id)) = self.compiler.ast_nodes[block.0] else { panic!("internal error: command definition's body is not a block"); }; self.resolve_block(block, block_id, Some(def_scope)); } - AstNode::Alias { + Stmt::Alias { new_name, old_name: _, } => { - self.define_decl(new_name); - } - AstNode::Params(ref params) => { - for param in params { - if let AstNode::Param { name, .. } = self.compiler.ast_nodes[param.0] { - self.define_variable(name, false); - } else { - panic!("param is not a param"); - } - } + self.define_decl(new_name, node_id); } - AstNode::Let { + Stmt::Let { variable_name, - ty: _, + ty, initializer, is_mutable, } => { self.resolve_node(initializer); + if let Some(ty) = ty { + self.resolve_node(ty); + } self.define_variable(variable_name, is_mutable) } - AstNode::While { condition, block } => { + Stmt::While { condition, block } => { self.resolve_node(condition); self.resolve_node(block); } - AstNode::For { + Stmt::For { variable, range, block, @@ -278,71 +440,17 @@ impl<'a> Resolver<'a> { self.resolve_node(range); - let AstNode::Block(block_id) = self.compiler.ast_nodes[block.0] else { + let AstNode::Expr(Expr::Block(block_id)) = self.compiler.ast_nodes[block.0] else { panic!("internal error: for's body is not a block"); }; self.resolve_block(block, block_id, Some(for_body_scope)); } - AstNode::Loop { block } => { + Stmt::Loop { block } => { self.resolve_node(block); } - AstNode::BinaryOp { lhs, op: _, rhs } => { - self.resolve_node(lhs); - self.resolve_node(rhs); - } - AstNode::Range { lhs, rhs } => { - self.resolve_node(lhs); - self.resolve_node(rhs); - } - AstNode::List(ref nodes) => { - for node in nodes { - self.resolve_node(*node); - } - } - AstNode::Table { header, ref rows } => { - self.resolve_node(header); - for row in rows { - self.resolve_node(*row); - } - } - AstNode::Record { ref pairs } => { - for (key, val) in pairs { - self.resolve_node(*key); - self.resolve_node(*val); - } - } - AstNode::MemberAccess { target, field } => { - self.resolve_node(target); - self.resolve_node(field); - } - AstNode::If { - condition, - then_block, - else_block, - } => { - self.resolve_node(condition); - self.resolve_node(then_block); - if let Some(block) = else_block { - self.resolve_node(block); - } - } - AstNode::Match { - target, - ref match_arms, - } => { - self.resolve_node(target); - for (arm_lhs, arm_rhs) in match_arms { - self.resolve_node(*arm_lhs); - self.resolve_node(*arm_rhs); - } - } - AstNode::Statement(node) => self.resolve_node(node), - AstNode::Param { .. } => (/* seems unused for now */), - AstNode::Type { .. } => ( /* probably doesn't make sense to resolve? */ ), - AstNode::NamedValue { .. } => (/* seems unused for now */), - // All remaining matches do not contain NodeId => there is nothing to resolve - _ => (), + Stmt::Expr(node) => self.resolve_node(node), + Stmt::Return(_) | Stmt::Break | Stmt::Continue => {} } } @@ -365,6 +473,31 @@ impl<'a> Resolver<'a> { } } + pub fn resolve_type(&mut self, unbound_node_id: NodeId) { + let type_name = self.compiler.get_span_contents(unbound_node_id); + + match type_name { + b"any" | b"list" | b"bool" | b"closure" | b"float" | b"int" | b"nothing" + | b"number" | b"string" => return, + _ => {} + } + + if let Some(node_id) = self.find_type(type_name) { + let type_id = self + .type_resolution + .get(&node_id) + .expect("internal error: missing resolved variable"); + + self.type_resolution.insert(unbound_node_id, *type_id); + } else { + self.errors.push(SourceError { + message: format!("type `{}` not found", String::from_utf8_lossy(type_name)), + node_id: unbound_node_id, + severity: Severity::Error, + }) + } + } + pub fn resolve_call(&mut self, unbound_node_id: NodeId, parts: &[NodeId]) { // Find out the potentially longest command name let max_name_parts = parts @@ -476,7 +609,26 @@ impl<'a> Resolver<'a> { self.var_resolution.insert(var_name_id, var_id); } - pub fn define_decl(&mut self, decl_name_id: NodeId) { + pub fn define_type_decl(&mut self, type_name_id: NodeId, type_decl: TypeDecl) { + let type_name = self.compiler.get_span_contents(type_name_id).to_vec(); + + let current_scope_id = self + .scope_stack + .last() + .expect("internal error: missing scope frame id"); + + self.scope[current_scope_id.0] + .type_decls + .insert(type_name, type_name_id); + + self.type_decls.push(type_decl); + let type_id = TypeDeclId(self.type_decls.len() - 1); + + // let the definition of a type also count as its use + self.type_resolution.insert(type_name_id, type_id); + } + + pub fn define_decl(&mut self, decl_name_id: NodeId, decl_node_id: NodeId) { // TODO: Deduplicate code with define_variable() let decl_name = self.compiler.get_span_contents(decl_name_id); let decl_name = trim_decl_name(decl_name).to_vec(); @@ -494,6 +646,8 @@ impl<'a> Resolver<'a> { self.decls.push(Box::new(decl)); let decl_id = DeclId(self.decls.len() - 1); + self.decl_nodes.push(decl_node_id); + // let the definition of a decl also count as its use self.decl_resolution.insert(decl_name_id, decl_id); } @@ -508,6 +662,16 @@ impl<'a> Resolver<'a> { None } + pub fn find_type(&self, type_name: &[u8]) -> Option { + for scope_id in self.scope_stack.iter().rev() { + if let Some(id) = self.scope[scope_id.0].type_decls.get(type_name) { + return Some(*id); + } + } + + None + } + pub fn find_decl(&self, var_name: &[u8]) -> Option { // TODO: Deduplicate code with find_variable() for scope_id in self.scope_stack.iter().rev() { diff --git a/src/snapshots/new_nu_parser__test__node_output@alias.nu.snap b/src/snapshots/new_nu_parser__test__node_output@alias.nu.snap index c26dc91..462e92b 100644 --- a/src/snapshots/new_nu_parser__test__node_output@alias.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@alias.nu.snap @@ -2,16 +2,15 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/alias.nu -snapshot_kind: text --- ==== COMPILER ==== -0: String (6 to 19) ""fancy alias"" +0: Expr(String) (6 to 19) ""fancy alias"" 1: Name (22 to 25) "foo" -2: Alias { new_name: NodeId(0), old_name: NodeId(1) } (0 to 25) +2: Stmt(Alias { new_name: NodeId(0), old_name: NodeId(1) }) (0 to 25) 3: Name (27 to 32) "fancy" 4: Name (33 to 38) "alias" -5: Call { parts: [NodeId(3), NodeId(4)] } (33 to 38) -6: Block(BlockId(0)) (0 to 39) +5: Expr(Call { parts: [NodeId(3), NodeId(4)] }) (33 to 38) +6: Expr(Block(BlockId(0))) (0 to 39) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(6) decls: [ fancy alias: NodeId(0) ] @@ -27,4 +26,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 2): node Alias { new_name: NodeId(0), old_name: NodeId(1) } not suported yet +Error (NodeId 2): node Stmt(Alias { new_name: NodeId(0), old_name: NodeId(1) }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@binary_ops_exact.nu.snap b/src/snapshots/new_nu_parser__test__node_output@binary_ops_exact.nu.snap index 9233e08..ce84e25 100644 --- a/src/snapshots/new_nu_parser__test__node_output@binary_ops_exact.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@binary_ops_exact.nu.snap @@ -2,41 +2,40 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/binary_ops_exact.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Int (0 to 1) "1" +0: Expr(Int) (0 to 1) "1" 1: Equal (2 to 4) -2: Int (5 to 6) "1" -3: BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) } (0 to 6) -4: True (8 to 12) -5: List([NodeId(4)]) (7 to 12) +2: Expr(Int) (5 to 6) "1" +3: Expr(BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) }) (0 to 6) +4: Expr(True) (8 to 12) +5: Expr(List([NodeId(4)])) (7 to 12) 6: Append (14 to 16) -7: False (17 to 22) -8: BinaryOp { lhs: NodeId(5), op: NodeId(6), rhs: NodeId(7) } (7 to 22) -9: Int (23 to 24) "1" +7: Expr(False) (17 to 22) +8: Expr(BinaryOp { lhs: NodeId(5), op: NodeId(6), rhs: NodeId(7) }) (7 to 22) +9: Expr(Int) (23 to 24) "1" 10: Plus (25 to 26) -11: Int (27 to 28) "1" -12: BinaryOp { lhs: NodeId(9), op: NodeId(10), rhs: NodeId(11) } (23 to 28) -13: Float (29 to 32) "1.0" +11: Expr(Int) (27 to 28) "1" +12: Expr(BinaryOp { lhs: NodeId(9), op: NodeId(10), rhs: NodeId(11) }) (23 to 28) +13: Expr(Float) (29 to 32) "1.0" 14: Plus (33 to 34) -15: Float (35 to 38) "1.0" -16: BinaryOp { lhs: NodeId(13), op: NodeId(14), rhs: NodeId(15) } (29 to 38) -17: True (39 to 43) +15: Expr(Float) (35 to 38) "1.0" +16: Expr(BinaryOp { lhs: NodeId(13), op: NodeId(14), rhs: NodeId(15) }) (29 to 38) +17: Expr(True) (39 to 43) 18: And (44 to 47) -19: False (48 to 53) -20: BinaryOp { lhs: NodeId(17), op: NodeId(18), rhs: NodeId(19) } (39 to 53) -21: String (54 to 59) ""foo"" +19: Expr(False) (48 to 53) +20: Expr(BinaryOp { lhs: NodeId(17), op: NodeId(18), rhs: NodeId(19) }) (39 to 53) +21: Expr(String) (54 to 59) ""foo"" 22: RegexMatch (60 to 62) -23: String (63 to 68) "".*o"" -24: BinaryOp { lhs: NodeId(21), op: NodeId(22), rhs: NodeId(23) } (54 to 68) -25: Int (69 to 70) "1" +23: Expr(String) (63 to 68) "".*o"" +24: Expr(BinaryOp { lhs: NodeId(21), op: NodeId(22), rhs: NodeId(23) }) (54 to 68) +25: Expr(Int) (69 to 70) "1" 26: In (71 to 73) -27: Int (75 to 76) "1" -28: Int (78 to 79) "2" -29: List([NodeId(27), NodeId(28)]) (74 to 79) -30: BinaryOp { lhs: NodeId(25), op: NodeId(26), rhs: NodeId(29) } (69 to 79) -31: Block(BlockId(0)) (0 to 81) +27: Expr(Int) (75 to 76) "1" +28: Expr(Int) (78 to 79) "2" +29: Expr(List([NodeId(27), NodeId(28)])) (74 to 79) +30: Expr(BinaryOp { lhs: NodeId(25), op: NodeId(26), rhs: NodeId(29) }) (69 to 79) +31: Expr(Block(BlockId(0))) (0 to 81) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(31) (empty) ==== TYPES ==== diff --git a/src/snapshots/new_nu_parser__test__node_output@binary_ops_mismatch.nu.snap b/src/snapshots/new_nu_parser__test__node_output@binary_ops_mismatch.nu.snap index fa39f5a..5b0b48e 100644 --- a/src/snapshots/new_nu_parser__test__node_output@binary_ops_mismatch.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@binary_ops_mismatch.nu.snap @@ -4,23 +4,23 @@ expression: evaluate_example(path) input_file: tests/binary_ops_mismatch.nu --- ==== COMPILER ==== -0: String (0 to 3) ""a"" +0: Expr(String) (0 to 3) ""a"" 1: Plus (4 to 5) -2: Float (6 to 9) "1.0" -3: BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) } (0 to 9) -4: String (10 to 13) ""a"" +2: Expr(Float) (6 to 9) "1.0" +3: Expr(BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) }) (0 to 9) +4: Expr(String) (10 to 13) ""a"" 5: Append (14 to 16) -6: Float (17 to 20) "1.0" -7: BinaryOp { lhs: NodeId(4), op: NodeId(5), rhs: NodeId(6) } (10 to 20) -8: True (21 to 25) +6: Expr(Float) (17 to 20) "1.0" +7: Expr(BinaryOp { lhs: NodeId(4), op: NodeId(5), rhs: NodeId(6) }) (10 to 20) +8: Expr(True) (21 to 25) 9: And (26 to 29) -10: String (30 to 33) ""a"" -11: BinaryOp { lhs: NodeId(8), op: NodeId(9), rhs: NodeId(10) } (21 to 33) -12: True (34 to 38) +10: Expr(String) (30 to 33) ""a"" +11: Expr(BinaryOp { lhs: NodeId(8), op: NodeId(9), rhs: NodeId(10) }) (21 to 33) +12: Expr(True) (34 to 38) 13: NotRegexMatch (39 to 41) -14: String (42 to 48) ""true"" -15: BinaryOp { lhs: NodeId(12), op: NodeId(13), rhs: NodeId(14) } (34 to 48) -16: Block(BlockId(0)) (0 to 49) +14: Expr(String) (42 to 48) ""true"" +15: Expr(BinaryOp { lhs: NodeId(12), op: NodeId(13), rhs: NodeId(14) }) (34 to 48) +16: Expr(Block(BlockId(0))) (0 to 49) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(16) (empty) ==== TYPES ==== @@ -50,4 +50,4 @@ Error (NodeId 13): type mismatch: unsupported string operation between bool and register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 0): node String not suported yet +Error (NodeId 0): node Expr(String) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@binary_ops_spaces.nu.snap b/src/snapshots/new_nu_parser__test__node_output@binary_ops_spaces.nu.snap index bfe066d..ef0c389 100644 --- a/src/snapshots/new_nu_parser__test__node_output@binary_ops_spaces.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@binary_ops_spaces.nu.snap @@ -2,26 +2,25 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/binary_ops_spaces.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Int (0 to 1) "1" +0: Expr(Int) (0 to 1) "1" 1: Plus (2 to 3) -2: Int (4 to 5) "2" -3: BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) } (0 to 5) -4: Int (6 to 7) "1" +2: Expr(Int) (4 to 5) "2" +3: Expr(BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) }) (0 to 5) +4: Expr(Int) (6 to 7) "1" 5: Plus (7 to 8) -6: Int (9 to 10) "2" -7: BinaryOp { lhs: NodeId(4), op: NodeId(5), rhs: NodeId(6) } (6 to 10) -8: Int (11 to 12) "1" +6: Expr(Int) (9 to 10) "2" +7: Expr(BinaryOp { lhs: NodeId(4), op: NodeId(5), rhs: NodeId(6) }) (6 to 10) +8: Expr(Int) (11 to 12) "1" 9: Plus (13 to 14) -10: Int (14 to 15) "2" -11: BinaryOp { lhs: NodeId(8), op: NodeId(9), rhs: NodeId(10) } (11 to 15) -12: Int (16 to 17) "1" +10: Expr(Int) (14 to 15) "2" +11: Expr(BinaryOp { lhs: NodeId(8), op: NodeId(9), rhs: NodeId(10) }) (11 to 15) +12: Expr(Int) (16 to 17) "1" 13: Plus (17 to 18) -14: Int (18 to 19) "2" -15: BinaryOp { lhs: NodeId(12), op: NodeId(13), rhs: NodeId(14) } (16 to 19) -16: Block(BlockId(0)) (0 to 20) +14: Expr(Int) (18 to 19) "2" +15: Expr(BinaryOp { lhs: NodeId(12), op: NodeId(13), rhs: NodeId(14) }) (16 to 19) +16: Expr(Block(BlockId(0))) (0 to 20) ==== COMPILER ERRORS ==== Error (NodeId 5): missing space before operator Error (NodeId 9): missing space after operator diff --git a/src/snapshots/new_nu_parser__test__node_output@binary_ops_subtypes.nu.snap b/src/snapshots/new_nu_parser__test__node_output@binary_ops_subtypes.nu.snap index 9c76012..556573c 100644 --- a/src/snapshots/new_nu_parser__test__node_output@binary_ops_subtypes.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@binary_ops_subtypes.nu.snap @@ -2,79 +2,78 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/binary_ops_subtypes.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Int (0 to 1) "1" +0: Expr(Int) (0 to 1) "1" 1: Equal (2 to 4) -2: Float (5 to 8) "1.0" -3: BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) } (0 to 8) -4: String (9 to 12) ""a"" +2: Expr(Float) (5 to 8) "1.0" +3: Expr(BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) }) (0 to 8) +4: Expr(String) (9 to 12) ""a"" 5: Equal (13 to 15) -6: Float (16 to 19) "1.0" -7: BinaryOp { lhs: NodeId(4), op: NodeId(5), rhs: NodeId(6) } (9 to 19) -8: Int (20 to 21) "1" +6: Expr(Float) (16 to 19) "1.0" +7: Expr(BinaryOp { lhs: NodeId(4), op: NodeId(5), rhs: NodeId(6) }) (9 to 19) +8: Expr(Int) (20 to 21) "1" 9: Plus (22 to 23) -10: Float (24 to 27) "1.0" -11: BinaryOp { lhs: NodeId(8), op: NodeId(9), rhs: NodeId(10) } (20 to 27) -12: Int (29 to 30) "1" -13: List([NodeId(12)]) (28 to 30) +10: Expr(Float) (24 to 27) "1.0" +11: Expr(BinaryOp { lhs: NodeId(8), op: NodeId(9), rhs: NodeId(10) }) (20 to 27) +12: Expr(Int) (29 to 30) "1" +13: Expr(List([NodeId(12)])) (28 to 30) 14: Append (32 to 34) -15: Float (35 to 38) "1.0" -16: BinaryOp { lhs: NodeId(13), op: NodeId(14), rhs: NodeId(15) } (28 to 38) -17: Float (40 to 43) "1.0" -18: Int (44 to 45) "1" -19: List([NodeId(17), NodeId(18)]) (39 to 45) +15: Expr(Float) (35 to 38) "1.0" +16: Expr(BinaryOp { lhs: NodeId(13), op: NodeId(14), rhs: NodeId(15) }) (28 to 38) +17: Expr(Float) (40 to 43) "1.0" +18: Expr(Int) (44 to 45) "1" +19: Expr(List([NodeId(17), NodeId(18)])) (39 to 45) 20: Append (47 to 49) -21: String (50 to 53) ""a"" -22: BinaryOp { lhs: NodeId(19), op: NodeId(20), rhs: NodeId(21) } (39 to 53) -23: Int (56 to 57) "1" -24: List([NodeId(23)]) (55 to 57) -25: Int (60 to 61) "2" -26: List([NodeId(25)]) (59 to 61) -27: List([NodeId(24), NodeId(26)]) (54 to 62) +21: Expr(String) (50 to 53) ""a"" +22: Expr(BinaryOp { lhs: NodeId(19), op: NodeId(20), rhs: NodeId(21) }) (39 to 53) +23: Expr(Int) (56 to 57) "1" +24: Expr(List([NodeId(23)])) (55 to 57) +25: Expr(Int) (60 to 61) "2" +26: Expr(List([NodeId(25)])) (59 to 61) +27: Expr(List([NodeId(24), NodeId(26)])) (54 to 62) 28: Append (64 to 66) -29: Int (69 to 70) "3" -30: List([NodeId(29)]) (68 to 70) -31: List([NodeId(30)]) (67 to 71) -32: BinaryOp { lhs: NodeId(27), op: NodeId(28), rhs: NodeId(31) } (54 to 71) -33: Int (75 to 76) "1" -34: List([NodeId(33)]) (74 to 76) -35: Int (79 to 80) "2" -36: List([NodeId(35)]) (78 to 80) -37: List([NodeId(34), NodeId(36)]) (73 to 81) +29: Expr(Int) (69 to 70) "3" +30: Expr(List([NodeId(29)])) (68 to 70) +31: Expr(List([NodeId(30)])) (67 to 71) +32: Expr(BinaryOp { lhs: NodeId(27), op: NodeId(28), rhs: NodeId(31) }) (54 to 71) +33: Expr(Int) (75 to 76) "1" +34: Expr(List([NodeId(33)])) (74 to 76) +35: Expr(Int) (79 to 80) "2" +36: Expr(List([NodeId(35)])) (78 to 80) +37: Expr(List([NodeId(34), NodeId(36)])) (73 to 81) 38: Append (83 to 85) -39: Float (88 to 91) "3.0" -40: List([NodeId(39)]) (87 to 91) -41: List([NodeId(40)]) (86 to 92) -42: BinaryOp { lhs: NodeId(37), op: NodeId(38), rhs: NodeId(41) } (73 to 92) -43: Int (94 to 95) "1" +39: Expr(Float) (88 to 91) "3.0" +40: Expr(List([NodeId(39)])) (87 to 91) +41: Expr(List([NodeId(40)])) (86 to 92) +42: Expr(BinaryOp { lhs: NodeId(37), op: NodeId(38), rhs: NodeId(41) }) (73 to 92) +43: Expr(Int) (94 to 95) "1" 44: In (96 to 98) -45: Float (100 to 103) "1.0" -46: Int (105 to 106) "1" -47: List([NodeId(45), NodeId(46)]) (99 to 106) -48: BinaryOp { lhs: NodeId(43), op: NodeId(44), rhs: NodeId(47) } (94 to 106) -49: Float (108 to 111) "2.3" +45: Expr(Float) (100 to 103) "1.0" +46: Expr(Int) (105 to 106) "1" +47: Expr(List([NodeId(45), NodeId(46)])) (99 to 106) +48: Expr(BinaryOp { lhs: NodeId(43), op: NodeId(44), rhs: NodeId(47) }) (94 to 106) +49: Expr(Float) (108 to 111) "2.3" 50: Modulo (112 to 115) -51: Int (116 to 117) "1" -52: BinaryOp { lhs: NodeId(49), op: NodeId(50), rhs: NodeId(51) } (108 to 117) -53: String (120 to 121) "b" -54: Int (123 to 124) "2" -55: String (126 to 127) "c" -56: Int (129 to 130) "3" -57: Record { pairs: [(NodeId(53), NodeId(54)), (NodeId(55), NodeId(56))] } (119 to 131) -58: List([NodeId(57)]) (118 to 131) +51: Expr(Int) (116 to 117) "1" +52: Expr(BinaryOp { lhs: NodeId(49), op: NodeId(50), rhs: NodeId(51) }) (108 to 117) +53: Expr(String) (120 to 121) "b" +54: Expr(Int) (123 to 124) "2" +55: Expr(String) (126 to 127) "c" +56: Expr(Int) (129 to 130) "3" +57: Expr(Record { pairs: [(NodeId(53), NodeId(54)), (NodeId(55), NodeId(56))] }) (119 to 131) +58: Expr(List([NodeId(57)])) (118 to 131) 59: Append (133 to 135) -60: String (138 to 139) "a" -61: Int (141 to 142) "3" -62: String (144 to 145) "b" -63: Float (147 to 150) "1.5" -64: String (152 to 153) "c" -65: String (155 to 160) ""foo"" -66: Record { pairs: [(NodeId(60), NodeId(61)), (NodeId(62), NodeId(63)), (NodeId(64), NodeId(65))] } (137 to 161) -67: List([NodeId(66)]) (136 to 161) -68: BinaryOp { lhs: NodeId(58), op: NodeId(59), rhs: NodeId(67) } (118 to 161) -69: Block(BlockId(0)) (0 to 163) +60: Expr(String) (138 to 139) "a" +61: Expr(Int) (141 to 142) "3" +62: Expr(String) (144 to 145) "b" +63: Expr(Float) (147 to 150) "1.5" +64: Expr(String) (152 to 153) "c" +65: Expr(String) (155 to 160) ""foo"" +66: Expr(Record { pairs: [(NodeId(60), NodeId(61)), (NodeId(62), NodeId(63)), (NodeId(64), NodeId(65))] }) (137 to 161) +67: Expr(List([NodeId(66)])) (136 to 161) +68: Expr(BinaryOp { lhs: NodeId(58), op: NodeId(59), rhs: NodeId(67) }) (118 to 161) +69: Expr(Block(BlockId(0))) (0 to 163) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(69) (empty) ==== TYPES ==== @@ -153,4 +152,4 @@ register_count: 1 file_count: 0 0: LoadLiteral { dst: RegId(0), lit: Int(1) } ==== IR ERRORS ==== -Error (NodeId 2): node Float not suported yet +Error (NodeId 2): node Expr(Float) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@calls.nu.snap b/src/snapshots/new_nu_parser__test__node_output@calls.nu.snap index d450b35..1508dd0 100644 --- a/src/snapshots/new_nu_parser__test__node_output@calls.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@calls.nu.snap @@ -6,44 +6,44 @@ input_file: tests/calls.nu ==== COMPILER ==== 0: Name (0 to 4) "spam" 1: Name (5 to 8) "foo" -2: String (9 to 14) ""bar"" -3: Int (16 to 17) "1" +2: Expr(String) (9 to 14) ""bar"" +3: Expr(Int) (16 to 17) "1" 4: Plus (18 to 19) -5: Int (20 to 21) "2" -6: BinaryOp { lhs: NodeId(3), op: NodeId(4), rhs: NodeId(5) } (16 to 21) -7: Call { parts: [NodeId(0), NodeId(1), NodeId(2), NodeId(6)] } (5 to 22) +5: Expr(Int) (20 to 21) "2" +6: Expr(BinaryOp { lhs: NodeId(3), op: NodeId(4), rhs: NodeId(5) }) (16 to 21) +7: Expr(Call { parts: [NodeId(0), NodeId(1), NodeId(2), NodeId(6)] }) (5 to 22) 8: Name (28 to 36) "existing" 9: Name (38 to 39) "a" 10: Name (41 to 47) "string" -11: Type { name: NodeId(10), args: None, optional: false } (41 to 47) +11: Type(Ref { name: NodeId(10), args: None, optional: false }) (41 to 47) 12: Param { name: NodeId(9), ty: Some(NodeId(11)) } (38 to 47) 13: Name (49 to 50) "b" 14: Name (52 to 58) "string" -15: Type { name: NodeId(14), args: None, optional: false } (52 to 58) +15: Type(Ref { name: NodeId(14), args: None, optional: false }) (52 to 58) 16: Param { name: NodeId(13), ty: Some(NodeId(15)) } (49 to 58) 17: Name (60 to 61) "c" 18: Name (63 to 66) "int" -19: Type { name: NodeId(18), args: None, optional: false } (63 to 66) +19: Type(Ref { name: NodeId(18), args: None, optional: false }) (63 to 66) 20: Param { name: NodeId(17), ty: Some(NodeId(19)) } (60 to 66) 21: Params([NodeId(12), NodeId(16), NodeId(20)]) (37 to 67) -22: Variable (72 to 74) "$a" -23: Variable (76 to 78) "$b" -24: Variable (80 to 82) "$c" -25: List([NodeId(22), NodeId(23), NodeId(24)]) (70 to 82) -26: Block(BlockId(0)) (68 to 85) -27: Def { name: NodeId(8), params: NodeId(21), in_out_types: None, block: NodeId(26) } (24 to 85) +22: Expr(VarRef) (72 to 74) "$a" +23: Expr(VarRef) (76 to 78) "$b" +24: Expr(VarRef) (80 to 82) "$c" +25: Expr(List([NodeId(22), NodeId(23), NodeId(24)])) (70 to 82) +26: Expr(Block(BlockId(0))) (68 to 85) +27: Stmt(Def { name: NodeId(8), type_params: None, params: NodeId(21), in_out_types: None, block: NodeId(26) }) (24 to 85) 28: Name (86 to 94) "existing" 29: Name (95 to 98) "foo" -30: String (100 to 104) ""ba"" +30: Expr(String) (100 to 104) ""ba"" 31: Plus (105 to 106) -32: String (107 to 110) ""r"" -33: BinaryOp { lhs: NodeId(30), op: NodeId(31), rhs: NodeId(32) } (100 to 110) -34: Int (112 to 113) "3" -35: Call { parts: [NodeId(28), NodeId(29), NodeId(33), NodeId(34)] } (95 to 113) +32: Expr(String) (107 to 110) ""r"" +33: Expr(BinaryOp { lhs: NodeId(30), op: NodeId(31), rhs: NodeId(32) }) (100 to 110) +34: Expr(Int) (112 to 113) "3" +35: Expr(Call { parts: [NodeId(28), NodeId(29), NodeId(33), NodeId(34)] }) (95 to 113) 36: Name (115 to 128) "foo/bar/spam " -37: Call { parts: [NodeId(36)] } (127 to 127) -38: Block(BlockId(1)) (0 to 128) +37: Expr(Call { parts: [NodeId(36)] }) (127 to 127) +38: Expr(Block(BlockId(1))) (0 to 128) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(38) decls: [ existing: NodeId(8) ] @@ -85,7 +85,7 @@ input_file: tests/calls.nu 32: string 33: string 34: int -35: any +35: list 36: unknown 37: stream 38: stream @@ -93,4 +93,4 @@ input_file: tests/calls.nu register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 7): node Call { parts: [NodeId(0), NodeId(1), NodeId(2), NodeId(6)] } not suported yet +Error (NodeId 7): node Expr(Call { parts: [NodeId(0), NodeId(1), NodeId(2), NodeId(6)] }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@calls_invalid.nu.snap b/src/snapshots/new_nu_parser__test__node_output@calls_invalid.nu.snap new file mode 100644 index 0000000..a685338 --- /dev/null +++ b/src/snapshots/new_nu_parser__test__node_output@calls_invalid.nu.snap @@ -0,0 +1,52 @@ +--- +source: src/test.rs +expression: evaluate_example(path) +input_file: tests/calls_invalid.nu +--- +==== COMPILER ==== +0: Name (4 to 7) "foo" +1: Name (10 to 11) "a" +2: Name (13 to 16) "int" +3: Type(Ref { name: NodeId(2), args: None, optional: false }) (13 to 16) +4: Param { name: NodeId(1), ty: Some(NodeId(3)) } (10 to 16) +5: Params([NodeId(4)]) (8 to 18) +6: Expr(Block(BlockId(0))) (19 to 21) +7: Stmt(Def { name: NodeId(0), type_params: None, params: NodeId(5), in_out_types: None, block: NodeId(6) }) (0 to 21) +8: Name (22 to 25) "foo" +9: Expr(Int) (26 to 27) "1" +10: Expr(Int) (28 to 29) "2" +11: Expr(Call { parts: [NodeId(8), NodeId(9), NodeId(10)] }) (26 to 29) +12: Name (30 to 33) "foo" +13: Expr(String) (34 to 42) ""string"" +14: Expr(Call { parts: [NodeId(12), NodeId(13)] }) (34 to 42) +15: Expr(Block(BlockId(1))) (0 to 43) +==== SCOPE ==== +0: Frame Scope, node_id: NodeId(15) + decls: [ foo: NodeId(0) ] +1: Frame Scope, node_id: NodeId(6) + variables: [ a: NodeId(1) ] +==== TYPES ==== +0: unknown +1: unknown +2: unknown +3: int +4: int +5: forbidden +6: () +7: () +8: unknown +9: int +10: unknown +11: () +12: unknown +13: string +14: () +15: () +==== TYPE ERRORS ==== +Error (NodeId 11): Expected 1 argument(s), got 2 +Error (NodeId 13): Expected int, got string +==== IR ==== +register_count: 0 +file_count: 0 +==== IR ERRORS ==== +Error (NodeId 7): node Stmt(Def { name: NodeId(0), type_params: None, params: NodeId(5), in_out_types: None, block: NodeId(6) }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@closure.nu.snap b/src/snapshots/new_nu_parser__test__node_output@closure.nu.snap index 00ef4a6..bce2fef 100644 --- a/src/snapshots/new_nu_parser__test__node_output@closure.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@closure.nu.snap @@ -2,7 +2,6 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/closure.nu -snapshot_kind: text --- ==== COMPILER ==== 0: Name (3 to 4) "a" @@ -10,14 +9,14 @@ snapshot_kind: text 2: Name (6 to 7) "b" 3: Param { name: NodeId(2), ty: None } (6 to 7) 4: Params([NodeId(1), NodeId(3)]) (2 to 8) -5: Variable (9 to 11) "$a" +5: Expr(VarRef) (9 to 11) "$a" 6: Plus (12 to 13) -7: Variable (14 to 16) "$b" -8: BinaryOp { lhs: NodeId(5), op: NodeId(6), rhs: NodeId(7) } (9 to 16) -9: Block(BlockId(0)) (9 to 16) -10: Closure { params: Some(NodeId(4)), block: NodeId(9) } (0 to 17) -11: Variable (18 to 20) "$a" -12: Block(BlockId(1)) (0 to 42) +7: Expr(VarRef) (14 to 16) "$b" +8: Expr(BinaryOp { lhs: NodeId(5), op: NodeId(6), rhs: NodeId(7) }) (9 to 16) +9: Expr(Block(BlockId(0))) (9 to 16) +10: Expr(Closure { params: Some(NodeId(4)), block: NodeId(9) }) (0 to 17) +11: Expr(VarRef) (18 to 20) "$a" +12: Expr(Block(BlockId(1))) (0 to 42) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(12) (empty) 1: Frame Scope, node_id: NodeId(9) diff --git a/src/snapshots/new_nu_parser__test__node_output@closure2.nu.snap b/src/snapshots/new_nu_parser__test__node_output@closure2.nu.snap index f192ad4..77bdc42 100644 --- a/src/snapshots/new_nu_parser__test__node_output@closure2.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@closure2.nu.snap @@ -2,16 +2,15 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/closure2.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Variable (4 to 6) "$a" +0: Expr(VarRef) (4 to 6) "$a" 1: Plus (7 to 8) -2: Variable (9 to 11) "$b" -3: BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) } (4 to 11) -4: Block(BlockId(0)) (4 to 12) -5: Closure { params: None, block: NodeId(4) } (0 to 13) -6: Block(BlockId(1)) (0 to 14) +2: Expr(VarRef) (9 to 11) "$b" +3: Expr(BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) }) (4 to 11) +4: Expr(Block(BlockId(0))) (4 to 12) +5: Expr(Closure { params: None, block: NodeId(4) }) (0 to 13) +6: Expr(Block(BlockId(1))) (0 to 14) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(6) (empty) 1: Frame Scope, node_id: NodeId(4) (empty) diff --git a/src/snapshots/new_nu_parser__test__node_output@closure3.nu.snap b/src/snapshots/new_nu_parser__test__node_output@closure3.nu.snap index 670e39c..82ad974 100644 --- a/src/snapshots/new_nu_parser__test__node_output@closure3.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@closure3.nu.snap @@ -4,30 +4,30 @@ expression: evaluate_example(path) input_file: tests/closure3.nu --- ==== COMPILER ==== -0: Variable (4 to 11) "closure" +0: VarDecl (4 to 11) "closure" 1: Name (16 to 17) "a" 2: Name (19 to 22) "int" -3: Type { name: NodeId(2), args: None, optional: false } (19 to 22) +3: Type(Ref { name: NodeId(2), args: None, optional: false }) (19 to 22) 4: Param { name: NodeId(1), ty: Some(NodeId(3)) } (16 to 22) 5: Name (24 to 25) "b" 6: Name (27 to 30) "int" -7: Type { name: NodeId(6), args: None, optional: false } (27 to 30) +7: Type(Ref { name: NodeId(6), args: None, optional: false }) (27 to 30) 8: Param { name: NodeId(5), ty: Some(NodeId(7)) } (24 to 30) 9: Params([NodeId(4), NodeId(8)]) (15 to 31) -10: Variable (32 to 34) "$a" +10: Expr(VarRef) (32 to 34) "$a" 11: Plus (35 to 36) -12: Variable (37 to 39) "$b" +12: Expr(VarRef) (37 to 39) "$b" 13: LessThan (40 to 41) -14: Int (42 to 43) "5" -15: BinaryOp { lhs: NodeId(10), op: NodeId(11), rhs: NodeId(12) } (32 to 39) -16: BinaryOp { lhs: NodeId(15), op: NodeId(13), rhs: NodeId(14) } (32 to 43) -17: Block(BlockId(0)) (32 to 43) -18: Closure { params: Some(NodeId(9)), block: NodeId(17) } (14 to 44) -19: Let { variable_name: NodeId(0), ty: None, initializer: NodeId(18), is_mutable: false } (0 to 44) +14: Expr(Int) (42 to 43) "5" +15: Expr(BinaryOp { lhs: NodeId(10), op: NodeId(11), rhs: NodeId(12) }) (32 to 39) +16: Expr(BinaryOp { lhs: NodeId(15), op: NodeId(13), rhs: NodeId(14) }) (32 to 43) +17: Expr(Block(BlockId(0))) (32 to 43) +18: Expr(Closure { params: Some(NodeId(9)), block: NodeId(17) }) (14 to 44) +19: Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(18), is_mutable: false }) (0 to 44) 20: Name (46 to 52) "filter" -21: Variable (53 to 61) "$closure" -22: Call { parts: [NodeId(20), NodeId(21)] } (53 to 61) -23: Block(BlockId(1)) (0 to 62) +21: Expr(VarRef) (53 to 61) "$closure" +22: Expr(Call { parts: [NodeId(20), NodeId(21)] }) (53 to 61) +23: Expr(Block(BlockId(1))) (0 to 62) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(23) variables: [ closure: NodeId(0) ] @@ -62,4 +62,4 @@ input_file: tests/closure3.nu register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 19): node Let { variable_name: NodeId(0), ty: None, initializer: NodeId(18), is_mutable: false } not suported yet +Error (NodeId 19): node Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(18), is_mutable: false }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@def.nu.snap b/src/snapshots/new_nu_parser__test__node_output@def.nu.snap index 12f3561..de1f4f9 100644 --- a/src/snapshots/new_nu_parser__test__node_output@def.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@def.nu.snap @@ -9,17 +9,17 @@ input_file: tests/def.nu 2: Param { name: NodeId(1), ty: None } (9 to 10) 3: Name (11 to 12) "x" 4: Name (14 to 17) "int" -5: Type { name: NodeId(4), args: None, optional: false } (14 to 17) +5: Type(Ref { name: NodeId(4), args: None, optional: false }) (14 to 17) 6: Param { name: NodeId(3), ty: Some(NodeId(5)) } (11 to 17) 7: Name (19 to 20) "y" 8: Name (22 to 26) "list" 9: Name (27 to 31) "list" 10: Name (32 to 35) "int" -11: Type { name: NodeId(10), args: None, optional: false } (32 to 35) +11: Type(Ref { name: NodeId(10), args: None, optional: false }) (32 to 35) 12: TypeArgs([NodeId(11)]) (31 to 36) -13: Type { name: NodeId(9), args: Some(NodeId(12)), optional: false } (27 to 31) +13: Type(Ref { name: NodeId(9), args: Some(NodeId(12)), optional: false }) (27 to 31) 14: TypeArgs([NodeId(13)]) (26 to 37) -15: Type { name: NodeId(8), args: Some(NodeId(14)), optional: false } (22 to 26) +15: Type(Ref { name: NodeId(8), args: Some(NodeId(14)), optional: false }) (22 to 26) 16: Param { name: NodeId(7), ty: Some(NodeId(15)) } (19 to 26) 17: Name (39 to 40) "z" 18: Name (42 to 48) "record" @@ -27,20 +27,20 @@ input_file: tests/def.nu 20: Param { name: NodeId(19), ty: None } (49 to 50) 21: Name (52 to 53) "b" 22: Name (55 to 58) "int" -23: Type { name: NodeId(22), args: None, optional: false } (55 to 58) +23: Type(Ref { name: NodeId(22), args: None, optional: false }) (55 to 58) 24: Param { name: NodeId(21), ty: Some(NodeId(23)) } (52 to 58) 25: Params([NodeId(20), NodeId(24)]) (48 to 59) -26: RecordType { fields: NodeId(25), optional: false } (42 to 60) +26: Type(Record { fields: NodeId(25), optional: false }) (42 to 60) 27: Param { name: NodeId(17), ty: Some(NodeId(26)) } (39 to 60) 28: Params([NodeId(2), NodeId(6), NodeId(16), NodeId(27)]) (8 to 61) -29: Variable (66 to 68) "$w" -30: Variable (69 to 71) "$x" -31: Variable (73 to 75) "$y" -32: Variable (77 to 79) "$z" -33: List([NodeId(29), NodeId(30), NodeId(31), NodeId(32)]) (64 to 80) -34: Block(BlockId(0)) (62 to 83) -35: Def { name: NodeId(0), params: NodeId(28), in_out_types: None, block: NodeId(34) } (0 to 83) -36: Block(BlockId(1)) (0 to 83) +29: Expr(VarRef) (66 to 68) "$w" +30: Expr(VarRef) (69 to 71) "$x" +31: Expr(VarRef) (73 to 75) "$y" +32: Expr(VarRef) (77 to 79) "$z" +33: Expr(List([NodeId(29), NodeId(30), NodeId(31), NodeId(32)])) (64 to 80) +34: Expr(Block(BlockId(0))) (62 to 83) +35: Stmt(Def { name: NodeId(0), type_params: None, params: NodeId(28), in_out_types: None, block: NodeId(34) }) (0 to 83) +36: Expr(Block(BlockId(1))) (0 to 83) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(36) decls: [ foo: NodeId(0) ] @@ -88,4 +88,4 @@ input_file: tests/def.nu register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 35): node Def { name: NodeId(0), params: NodeId(28), in_out_types: None, block: NodeId(34) } not suported yet +Error (NodeId 35): node Stmt(Def { name: NodeId(0), type_params: None, params: NodeId(28), in_out_types: None, block: NodeId(34) }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@def_generics.nu.snap b/src/snapshots/new_nu_parser__test__node_output@def_generics.nu.snap new file mode 100644 index 0000000..e1812e3 --- /dev/null +++ b/src/snapshots/new_nu_parser__test__node_output@def_generics.nu.snap @@ -0,0 +1,72 @@ +--- +source: src/test.rs +expression: evaluate_example(path) +input_file: tests/def_generics.nu +--- +==== COMPILER ==== +0: Name (4 to 5) "f" +1: Name (6 to 7) "T" +2: TypeParams([NodeId(1)]) (5 to 8) +3: Name (11 to 12) "x" +4: Name (14 to 15) "T" +5: Type(Ref { name: NodeId(4), args: None, optional: false }) (14 to 15) +6: Param { name: NodeId(3), ty: Some(NodeId(5)) } (11 to 15) +7: Params([NodeId(6)]) (9 to 17) +8: Name (20 to 27) "nothing" +9: Type(Ref { name: NodeId(8), args: None, optional: false }) (20 to 27) +10: Name (31 to 35) "list" +11: Name (36 to 37) "T" +12: Type(Ref { name: NodeId(11), args: None, optional: false }) (36 to 37) +13: TypeArgs([NodeId(12)]) (35 to 38) +14: Type(Ref { name: NodeId(10), args: Some(NodeId(13)), optional: false }) (31 to 35) +15: InOutType(NodeId(9), NodeId(14)) (20 to 39) +16: InOutTypes([NodeId(15)]) (20 to 39) +17: VarDecl (47 to 48) "z" +18: Name (50 to 51) "T" +19: Type(Ref { name: NodeId(18), args: None, optional: false }) (50 to 51) +20: Expr(VarRef) (54 to 56) "$x" +21: Stmt(Let { variable_name: NodeId(17), ty: Some(NodeId(19)), initializer: NodeId(20), is_mutable: false }) (43 to 56) +22: Expr(VarRef) (60 to 62) "$z" +23: Expr(List([NodeId(22)])) (59 to 62) +24: Expr(Block(BlockId(0))) (39 to 65) +25: Stmt(Def { name: NodeId(0), type_params: Some(NodeId(2)), params: NodeId(7), in_out_types: Some(NodeId(16)), block: NodeId(24) }) (0 to 65) +26: Expr(Block(BlockId(1))) (0 to 66) +==== SCOPE ==== +0: Frame Scope, node_id: NodeId(26) + decls: [ f: NodeId(0) ] +1: Frame Scope, node_id: NodeId(24) + variables: [ x: NodeId(3), z: NodeId(17) ] + type decls: [ T: NodeId(1) ] +==== TYPES ==== +0: unknown +1: unknown +2: unknown +3: unknown +4: unknown +5: T +6: T +7: forbidden +8: unknown +9: nothing +10: unknown +11: unknown +12: T +13: forbidden +14: list +15: unknown +16: unknown +17: T +18: unknown +19: T +20: T +21: () +22: T +23: list +24: list +25: () +26: () +==== IR ==== +register_count: 0 +file_count: 0 +==== IR ERRORS ==== +Error (NodeId 25): node Stmt(Def { name: NodeId(0), type_params: Some(NodeId(2)), params: NodeId(7), in_out_types: Some(NodeId(16)), block: NodeId(24) }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@def_return_type.nu.snap b/src/snapshots/new_nu_parser__test__node_output@def_return_type.nu.snap index a73afae..9fee6a5 100644 --- a/src/snapshots/new_nu_parser__test__node_output@def_return_type.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@def_return_type.nu.snap @@ -7,40 +7,40 @@ input_file: tests/def_return_type.nu 0: Name (4 to 7) "foo" 1: Params([]) (8 to 11) 2: Name (14 to 21) "nothing" -3: Type { name: NodeId(2), args: None, optional: false } (14 to 21) +3: Type(Ref { name: NodeId(2), args: None, optional: false }) (14 to 21) 4: Name (25 to 29) "list" 5: Name (30 to 33) "any" -6: Type { name: NodeId(5), args: None, optional: false } (30 to 33) +6: Type(Ref { name: NodeId(5), args: None, optional: false }) (30 to 33) 7: TypeArgs([NodeId(6)]) (29 to 34) -8: Type { name: NodeId(4), args: Some(NodeId(7)), optional: false } (25 to 29) +8: Type(Ref { name: NodeId(4), args: Some(NodeId(7)), optional: false }) (25 to 29) 9: InOutType(NodeId(3), NodeId(8)) (14 to 35) 10: InOutTypes([NodeId(9)]) (14 to 35) -11: List([]) (37 to 38) -12: Block(BlockId(0)) (35 to 41) -13: Def { name: NodeId(0), params: NodeId(1), in_out_types: Some(NodeId(10)), block: NodeId(12) } (0 to 41) +11: Expr(List([])) (37 to 38) +12: Expr(Block(BlockId(0))) (35 to 41) +13: Stmt(Def { name: NodeId(0), type_params: None, params: NodeId(1), in_out_types: Some(NodeId(10)), block: NodeId(12) }) (0 to 41) 14: Name (46 to 49) "bar" 15: Params([]) (50 to 53) 16: Name (58 to 64) "string" -17: Type { name: NodeId(16), args: None, optional: false } (58 to 64) +17: Type(Ref { name: NodeId(16), args: None, optional: false }) (58 to 64) 18: Name (68 to 72) "list" 19: Name (73 to 79) "string" -20: Type { name: NodeId(19), args: None, optional: false } (73 to 79) +20: Type(Ref { name: NodeId(19), args: None, optional: false }) (73 to 79) 21: TypeArgs([NodeId(20)]) (72 to 80) -22: Type { name: NodeId(18), args: Some(NodeId(21)), optional: false } (68 to 72) +22: Type(Ref { name: NodeId(18), args: Some(NodeId(21)), optional: false }) (68 to 72) 23: InOutType(NodeId(17), NodeId(22)) (58 to 80) 24: Name (82 to 85) "int" -25: Type { name: NodeId(24), args: None, optional: false } (82 to 85) +25: Type(Ref { name: NodeId(24), args: None, optional: false }) (82 to 85) 26: Name (89 to 93) "list" 27: Name (94 to 97) "int" -28: Type { name: NodeId(27), args: None, optional: false } (94 to 97) +28: Type(Ref { name: NodeId(27), args: None, optional: false }) (94 to 97) 29: TypeArgs([NodeId(28)]) (93 to 98) -30: Type { name: NodeId(26), args: Some(NodeId(29)), optional: false } (89 to 93) +30: Type(Ref { name: NodeId(26), args: Some(NodeId(29)), optional: false }) (89 to 93) 31: InOutType(NodeId(25), NodeId(30)) (82 to 99) 32: InOutTypes([NodeId(23), NodeId(31)]) (56 to 101) -33: List([]) (103 to 104) -34: Block(BlockId(1)) (101 to 107) -35: Def { name: NodeId(14), params: NodeId(15), in_out_types: Some(NodeId(32)), block: NodeId(34) } (42 to 107) -36: Block(BlockId(2)) (0 to 108) +33: Expr(List([])) (103 to 104) +34: Expr(Block(BlockId(1))) (101 to 107) +35: Stmt(Def { name: NodeId(14), type_params: None, params: NodeId(15), in_out_types: Some(NodeId(32)), block: NodeId(34) }) (42 to 107) +36: Expr(Block(BlockId(2))) (0 to 108) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(36) decls: [ bar: NodeId(14), foo: NodeId(0) ] @@ -50,12 +50,12 @@ input_file: tests/def_return_type.nu 0: unknown 1: forbidden 2: unknown -3: unknown +3: nothing 4: unknown 5: unknown 6: any 7: forbidden -8: unknown +8: list 9: unknown 10: unknown 11: list @@ -64,20 +64,20 @@ input_file: tests/def_return_type.nu 14: unknown 15: forbidden 16: unknown -17: unknown +17: string 18: unknown 19: unknown 20: string 21: forbidden -22: unknown +22: list 23: unknown 24: unknown -25: unknown +25: int 26: unknown 27: unknown 28: int 29: forbidden -30: unknown +30: list 31: unknown 32: unknown 33: list @@ -88,4 +88,4 @@ input_file: tests/def_return_type.nu register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 13): node Def { name: NodeId(0), params: NodeId(1), in_out_types: Some(NodeId(10)), block: NodeId(12) } not suported yet +Error (NodeId 13): node Stmt(Def { name: NodeId(0), type_params: None, params: NodeId(1), in_out_types: Some(NodeId(10)), block: NodeId(12) }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@for.nu.snap b/src/snapshots/new_nu_parser__test__node_output@for.nu.snap index 75889ed..04cd2c7 100644 --- a/src/snapshots/new_nu_parser__test__node_output@for.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@for.nu.snap @@ -2,41 +2,40 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/for.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Variable (4 to 5) "x" -1: Int (8 to 9) "0" -2: Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true } (0 to 9) -3: Variable (14 to 15) "i" -4: Int (20 to 21) "1" -5: Int (22 to 23) "2" -6: Int (24 to 25) "3" -7: List([NodeId(4), NodeId(5), NodeId(6)]) (19 to 25) -8: Variable (33 to 35) "$x" +0: VarDecl (4 to 5) "x" +1: Expr(Int) (8 to 9) "0" +2: Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true }) (0 to 9) +3: VarDecl (14 to 15) "i" +4: Expr(Int) (20 to 21) "1" +5: Expr(Int) (22 to 23) "2" +6: Expr(Int) (24 to 25) "3" +7: Expr(List([NodeId(4), NodeId(5), NodeId(6)])) (19 to 25) +8: Expr(VarRef) (33 to 35) "$x" 9: Assignment (36 to 37) -10: Variable (38 to 40) "$x" +10: Expr(VarRef) (38 to 40) "$x" 11: Plus (41 to 42) -12: Variable (43 to 45) "$i" -13: BinaryOp { lhs: NodeId(10), op: NodeId(11), rhs: NodeId(12) } (38 to 45) -14: BinaryOp { lhs: NodeId(8), op: NodeId(9), rhs: NodeId(13) } (33 to 45) -15: Block(BlockId(0)) (27 to 47) -16: For { variable: NodeId(3), range: NodeId(7), block: NodeId(15) } (10 to 47) -17: Variable (53 to 55) "$i" -18: Int (60 to 61) "4" -19: Int (62 to 63) "5" -20: Int (64 to 65) "6" -21: List([NodeId(18), NodeId(19), NodeId(20)]) (59 to 65) -22: Variable (73 to 75) "$x" +12: Expr(VarRef) (43 to 45) "$i" +13: Expr(BinaryOp { lhs: NodeId(10), op: NodeId(11), rhs: NodeId(12) }) (38 to 45) +14: Expr(BinaryOp { lhs: NodeId(8), op: NodeId(9), rhs: NodeId(13) }) (33 to 45) +15: Expr(Block(BlockId(0))) (27 to 47) +16: Stmt(For { variable: NodeId(3), range: NodeId(7), block: NodeId(15) }) (10 to 47) +17: VarDecl (53 to 55) "$i" +18: Expr(Int) (60 to 61) "4" +19: Expr(Int) (62 to 63) "5" +20: Expr(Int) (64 to 65) "6" +21: Expr(List([NodeId(18), NodeId(19), NodeId(20)])) (59 to 65) +22: Expr(VarRef) (73 to 75) "$x" 23: Assignment (76 to 77) -24: Variable (78 to 80) "$x" +24: Expr(VarRef) (78 to 80) "$x" 25: Plus (81 to 82) -26: Variable (83 to 85) "$i" -27: BinaryOp { lhs: NodeId(24), op: NodeId(25), rhs: NodeId(26) } (78 to 85) -28: BinaryOp { lhs: NodeId(22), op: NodeId(23), rhs: NodeId(27) } (73 to 85) -29: Block(BlockId(1)) (67 to 87) -30: For { variable: NodeId(17), range: NodeId(21), block: NodeId(29) } (49 to 87) -31: Block(BlockId(2)) (0 to 88) +26: Expr(VarRef) (83 to 85) "$i" +27: Expr(BinaryOp { lhs: NodeId(24), op: NodeId(25), rhs: NodeId(26) }) (78 to 85) +28: Expr(BinaryOp { lhs: NodeId(22), op: NodeId(23), rhs: NodeId(27) }) (73 to 85) +29: Expr(Block(BlockId(1))) (67 to 87) +30: Stmt(For { variable: NodeId(17), range: NodeId(21), block: NodeId(29) }) (49 to 87) +31: Expr(Block(BlockId(2))) (0 to 88) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(31) variables: [ x: NodeId(0) ] @@ -81,4 +80,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 2): node Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true } not suported yet +Error (NodeId 2): node Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@for_break_continue.nu.snap b/src/snapshots/new_nu_parser__test__node_output@for_break_continue.nu.snap index 86ad7e5..bc56be7 100644 --- a/src/snapshots/new_nu_parser__test__node_output@for_break_continue.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@for_break_continue.nu.snap @@ -2,41 +2,40 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/for_break_continue.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Variable (4 to 5) "x" -1: Int (8 to 9) "0" -2: Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true } (0 to 9) -3: Variable (14 to 15) "i" -4: Int (20 to 21) "1" -5: Int (22 to 23) "2" -6: Int (24 to 25) "3" -7: List([NodeId(4), NodeId(5), NodeId(6)]) (19 to 25) -8: Variable (36 to 38) "$x" +0: VarDecl (4 to 5) "x" +1: Expr(Int) (8 to 9) "0" +2: Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true }) (0 to 9) +3: VarDecl (14 to 15) "i" +4: Expr(Int) (20 to 21) "1" +5: Expr(Int) (22 to 23) "2" +6: Expr(Int) (24 to 25) "3" +7: Expr(List([NodeId(4), NodeId(5), NodeId(6)])) (19 to 25) +8: Expr(VarRef) (36 to 38) "$x" 9: GreaterThan (39 to 40) -10: Int (41 to 42) "2" -11: BinaryOp { lhs: NodeId(8), op: NodeId(9), rhs: NodeId(10) } (36 to 42) -12: Break (53 to 58) -13: Block(BlockId(0)) (43 to 64) -14: If { condition: NodeId(11), then_block: NodeId(13), else_block: None } (33 to 64) -15: Variable (73 to 75) "$i" +10: Expr(Int) (41 to 42) "2" +11: Expr(BinaryOp { lhs: NodeId(8), op: NodeId(9), rhs: NodeId(10) }) (36 to 42) +12: Stmt(Break) (53 to 58) +13: Expr(Block(BlockId(0))) (43 to 64) +14: Expr(If { condition: NodeId(11), then_block: NodeId(13), else_block: None }) (33 to 64) +15: Expr(VarRef) (73 to 75) "$i" 16: LessThan (76 to 77) -17: Int (78 to 79) "3" -18: BinaryOp { lhs: NodeId(15), op: NodeId(16), rhs: NodeId(17) } (73 to 79) -19: Continue (90 to 98) -20: Block(BlockId(1)) (80 to 104) -21: If { condition: NodeId(18), then_block: NodeId(20), else_block: None } (70 to 104) -22: Variable (110 to 112) "$x" +17: Expr(Int) (78 to 79) "3" +18: Expr(BinaryOp { lhs: NodeId(15), op: NodeId(16), rhs: NodeId(17) }) (73 to 79) +19: Stmt(Continue) (90 to 98) +20: Expr(Block(BlockId(1))) (80 to 104) +21: Expr(If { condition: NodeId(18), then_block: NodeId(20), else_block: None }) (70 to 104) +22: Expr(VarRef) (110 to 112) "$x" 23: Assignment (113 to 114) -24: Variable (115 to 117) "$x" +24: Expr(VarRef) (115 to 117) "$x" 25: Plus (118 to 119) -26: Variable (120 to 122) "$i" -27: BinaryOp { lhs: NodeId(24), op: NodeId(25), rhs: NodeId(26) } (115 to 122) -28: BinaryOp { lhs: NodeId(22), op: NodeId(23), rhs: NodeId(27) } (110 to 122) -29: Block(BlockId(2)) (27 to 124) -30: For { variable: NodeId(3), range: NodeId(7), block: NodeId(29) } (10 to 124) -31: Block(BlockId(3)) (0 to 124) +26: Expr(VarRef) (120 to 122) "$i" +27: Expr(BinaryOp { lhs: NodeId(24), op: NodeId(25), rhs: NodeId(26) }) (115 to 122) +28: Expr(BinaryOp { lhs: NodeId(22), op: NodeId(23), rhs: NodeId(27) }) (110 to 122) +29: Expr(Block(BlockId(2))) (27 to 124) +30: Stmt(For { variable: NodeId(3), range: NodeId(7), block: NodeId(29) }) (10 to 124) +31: Expr(Block(BlockId(3))) (0 to 124) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(31) variables: [ x: NodeId(0) ] @@ -58,15 +57,15 @@ snapshot_kind: text 10: int 11: bool 12: unknown -13: unknown -14: oneof<(), unknown> +13: () +14: () 15: int 16: forbidden 17: int 18: bool 19: unknown -20: unknown -21: oneof<(), unknown> +20: () +21: () 22: int 23: forbidden 24: int @@ -78,10 +77,10 @@ snapshot_kind: text 30: () 31: () ==== TYPE ERRORS ==== -Error (NodeId 12): unsupported ast node 'Break' in typechecker -Error (NodeId 19): unsupported ast node 'Continue' in typechecker +Error (NodeId 12): unsupported ast node 'Stmt(Break)' in typechecker +Error (NodeId 19): unsupported ast node 'Stmt(Continue)' in typechecker ==== IR ==== register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 2): node Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true } not suported yet +Error (NodeId 2): node Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@if_.nu.snap b/src/snapshots/new_nu_parser__test__node_output@if_.nu.snap index 6eada57..e41b620 100644 --- a/src/snapshots/new_nu_parser__test__node_output@if_.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@if_.nu.snap @@ -2,29 +2,28 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/if_.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Variable (4 to 5) "x" -1: Int (8 to 11) "123" -2: Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: false } (0 to 11) -3: Variable (16 to 18) "$x" +0: VarDecl (4 to 5) "x" +1: Expr(Int) (8 to 11) "123" +2: Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: false }) (0 to 11) +3: Expr(VarRef) (16 to 18) "$x" 4: LessThan (19 to 20) -5: Int (21 to 24) "100" -6: BinaryOp { lhs: NodeId(3), op: NodeId(4), rhs: NodeId(5) } (16 to 24) -7: Int (31 to 32) "5" -8: Block(BlockId(0)) (25 to 35) -9: Variable (43 to 45) "$x" +5: Expr(Int) (21 to 24) "100" +6: Expr(BinaryOp { lhs: NodeId(3), op: NodeId(4), rhs: NodeId(5) }) (16 to 24) +7: Expr(Int) (31 to 32) "5" +8: Expr(Block(BlockId(0))) (25 to 35) +9: Expr(VarRef) (43 to 45) "$x" 10: GreaterThan (46 to 47) -11: Int (48 to 51) "200" -12: BinaryOp { lhs: NodeId(9), op: NodeId(10), rhs: NodeId(11) } (43 to 51) -13: Int (58 to 59) "6" -14: Block(BlockId(1)) (52 to 62) -15: Int (73 to 74) "7" -16: Block(BlockId(2)) (67 to 76) -17: If { condition: NodeId(12), then_block: NodeId(14), else_block: Some(NodeId(16)) } (40 to 76) -18: If { condition: NodeId(6), then_block: NodeId(8), else_block: Some(NodeId(17)) } (13 to 76) -19: Block(BlockId(3)) (0 to 77) +11: Expr(Int) (48 to 51) "200" +12: Expr(BinaryOp { lhs: NodeId(9), op: NodeId(10), rhs: NodeId(11) }) (43 to 51) +13: Expr(Int) (58 to 59) "6" +14: Expr(Block(BlockId(1))) (52 to 62) +15: Expr(Int) (73 to 74) "7" +16: Expr(Block(BlockId(2))) (67 to 76) +17: Expr(If { condition: NodeId(12), then_block: NodeId(14), else_block: Some(NodeId(16)) }) (40 to 76) +18: Expr(If { condition: NodeId(6), then_block: NodeId(8), else_block: Some(NodeId(17)) }) (13 to 76) +19: Expr(Block(BlockId(3))) (0 to 77) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(19) variables: [ x: NodeId(0) ] @@ -56,4 +55,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 2): node Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: false } not suported yet +Error (NodeId 2): node Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: false }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@invalid_if.nu.snap b/src/snapshots/new_nu_parser__test__node_output@invalid_if.nu.snap index e96d1b5..60dd98d 100644 --- a/src/snapshots/new_nu_parser__test__node_output@invalid_if.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@invalid_if.nu.snap @@ -2,16 +2,15 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/invalid_if.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Int (3 to 4) "1" -1: Int (9 to 10) "4" -2: Block(BlockId(0)) (5 to 13) -3: Int (22 to 23) "3" -4: Block(BlockId(1)) (18 to 25) -5: If { condition: NodeId(0), then_block: NodeId(2), else_block: Some(NodeId(4)) } (0 to 25) -6: Block(BlockId(2)) (0 to 26) +0: Expr(Int) (3 to 4) "1" +1: Expr(Int) (9 to 10) "4" +2: Expr(Block(BlockId(0))) (5 to 13) +3: Expr(Int) (22 to 23) "3" +4: Expr(Block(BlockId(1))) (18 to 25) +5: Expr(If { condition: NodeId(0), then_block: NodeId(2), else_block: Some(NodeId(4)) }) (0 to 25) +6: Expr(Block(BlockId(2))) (0 to 26) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(6) (empty) 1: Frame Scope, node_id: NodeId(2) (empty) @@ -22,12 +21,12 @@ snapshot_kind: text 2: int 3: int 4: int -5: error -6: error +5: int +6: int ==== TYPE ERRORS ==== -Error (NodeId 0): The condition for if branch is not a boolean +Error (NodeId 0): Expected bool, got int ==== IR ==== register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 5): node If { condition: NodeId(0), then_block: NodeId(2), else_block: Some(NodeId(4)) } not suported yet +Error (NodeId 5): node Expr(If { condition: NodeId(0), then_block: NodeId(2), else_block: Some(NodeId(4)) }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@invalid_range.nu.snap b/src/snapshots/new_nu_parser__test__node_output@invalid_range.nu.snap index c5d3a4c..27190be 100644 --- a/src/snapshots/new_nu_parser__test__node_output@invalid_range.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@invalid_range.nu.snap @@ -2,12 +2,11 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/invalid_range.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Int (0 to 1) "1" +0: Expr(Int) (0 to 1) "1" 1: Garbage (2 to 4) -2: Int (5 to 6) "2" -3: Block(BlockId(0)) (0 to 7) +2: Expr(Int) (5 to 6) "2" +3: Expr(Block(BlockId(0))) (0 to 7) ==== COMPILER ERRORS ==== Error (NodeId 1): incomplete expression diff --git a/src/snapshots/new_nu_parser__test__node_output@invalid_record.nu.snap b/src/snapshots/new_nu_parser__test__node_output@invalid_record.nu.snap index f8b4411..29fe7c4 100644 --- a/src/snapshots/new_nu_parser__test__node_output@invalid_record.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@invalid_record.nu.snap @@ -2,16 +2,15 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/invalid_record.nu -snapshot_kind: text --- ==== COMPILER ==== -0: String (2 to 3) "a" -1: Int (5 to 6) "1" -2: String (9 to 10) "b" +0: Expr(String) (2 to 3) "a" +1: Expr(Int) (5 to 6) "1" +2: Expr(String) (9 to 10) "b" 3: Garbage (11 to 12) 4: Garbage (13 to 13) -5: Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(4))] } (0 to 0) -6: Block(BlockId(0)) (0 to 13) +5: Expr(Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(4))] }) (0 to 0) +6: Expr(Block(BlockId(0))) (0 to 13) ==== COMPILER ERRORS ==== Error (NodeId 3): expected: colon ':' Error (NodeId 4): incomplete expression diff --git a/src/snapshots/new_nu_parser__test__node_output@invalid_types.nu.snap b/src/snapshots/new_nu_parser__test__node_output@invalid_types.nu.snap index 89de622..9d1cee3 100644 --- a/src/snapshots/new_nu_parser__test__node_output@invalid_types.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@invalid_types.nu.snap @@ -8,27 +8,27 @@ input_file: tests/invalid_types.nu 1: Name (9 to 10) "x" 2: Name (12 to 16) "list" 3: Name (17 to 20) "int" -4: Type { name: NodeId(3), args: None, optional: false } (17 to 20) +4: Type(Ref { name: NodeId(3), args: None, optional: false }) (17 to 20) 5: Name (22 to 28) "string" -6: Type { name: NodeId(5), args: None, optional: false } (22 to 28) +6: Type(Ref { name: NodeId(5), args: None, optional: false }) (22 to 28) 7: TypeArgs([NodeId(4), NodeId(6)]) (16 to 29) -8: Type { name: NodeId(2), args: Some(NodeId(7)), optional: false } (12 to 16) +8: Type(Ref { name: NodeId(2), args: Some(NodeId(7)), optional: false }) (12 to 16) 9: Param { name: NodeId(1), ty: Some(NodeId(8)) } (9 to 16) 10: Params([NodeId(9)]) (8 to 30) -11: Variable (33 to 35) "$x" -12: Block(BlockId(0)) (31 to 37) -13: Def { name: NodeId(0), params: NodeId(10), in_out_types: None, block: NodeId(12) } (0 to 37) +11: Expr(VarRef) (33 to 35) "$x" +12: Expr(Block(BlockId(0))) (31 to 37) +13: Stmt(Def { name: NodeId(0), type_params: None, params: NodeId(10), in_out_types: None, block: NodeId(12) }) (0 to 37) 14: Name (42 to 45) "bar" 15: Name (47 to 48) "y" 16: Name (50 to 54) "list" 17: TypeArgs([]) (54 to 56) -18: Type { name: NodeId(16), args: Some(NodeId(17)), optional: false } (50 to 54) +18: Type(Ref { name: NodeId(16), args: Some(NodeId(17)), optional: false }) (50 to 54) 19: Param { name: NodeId(15), ty: Some(NodeId(18)) } (47 to 54) 20: Params([NodeId(19)]) (46 to 57) -21: Variable (60 to 62) "$y" -22: Block(BlockId(1)) (58 to 64) -23: Def { name: NodeId(14), params: NodeId(20), in_out_types: None, block: NodeId(22) } (38 to 64) -24: Block(BlockId(2)) (0 to 65) +21: Expr(VarRef) (60 to 62) "$y" +22: Expr(Block(BlockId(1))) (58 to 64) +23: Stmt(Def { name: NodeId(14), type_params: None, params: NodeId(20), in_out_types: None, block: NodeId(22) }) (38 to 64) +24: Expr(Block(BlockId(2))) (0 to 65) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(24) decls: [ bar: NodeId(14), foo: NodeId(0) ] @@ -69,4 +69,4 @@ Error (NodeId 17): list must have one type argument register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 13): node Def { name: NodeId(0), params: NodeId(10), in_out_types: None, block: NodeId(12) } not suported yet +Error (NodeId 13): node Stmt(Def { name: NodeId(0), type_params: None, params: NodeId(10), in_out_types: None, block: NodeId(12) }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@let_.nu.snap b/src/snapshots/new_nu_parser__test__node_output@let_.nu.snap index c151562..eb2186e 100644 --- a/src/snapshots/new_nu_parser__test__node_output@let_.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@let_.nu.snap @@ -2,14 +2,13 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/let_.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Variable (4 to 5) "x" -1: Int (8 to 11) "123" -2: Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: false } (0 to 11) -3: Variable (13 to 15) "$x" -4: Block(BlockId(0)) (0 to 15) +0: VarDecl (4 to 5) "x" +1: Expr(Int) (8 to 11) "123" +2: Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: false }) (0 to 11) +3: Expr(VarRef) (13 to 15) "$x" +4: Expr(Block(BlockId(0))) (0 to 15) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(4) variables: [ x: NodeId(0) ] @@ -23,4 +22,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 2): node Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: false } not suported yet +Error (NodeId 2): node Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: false }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@let_mismatch.nu.snap b/src/snapshots/new_nu_parser__test__node_output@let_mismatch.nu.snap index 429b553..4b9ae43 100644 --- a/src/snapshots/new_nu_parser__test__node_output@let_mismatch.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@let_mismatch.nu.snap @@ -4,47 +4,47 @@ expression: evaluate_example(path) input_file: tests/let_mismatch.nu --- ==== COMPILER ==== -0: Variable (4 to 5) "x" +0: VarDecl (4 to 5) "x" 1: Name (7 to 13) "number" -2: Type { name: NodeId(1), args: None, optional: false } (7 to 13) -3: Int (16 to 18) "10" -4: Let { variable_name: NodeId(0), ty: Some(NodeId(2)), initializer: NodeId(3), is_mutable: false } (0 to 18) -5: Variable (32 to 33) "y" +2: Type(Ref { name: NodeId(1), args: None, optional: false }) (7 to 13) +3: Expr(Int) (16 to 18) "10" +4: Stmt(Let { variable_name: NodeId(0), ty: Some(NodeId(2)), initializer: NodeId(3), is_mutable: false }) (0 to 18) +5: VarDecl (32 to 33) "y" 6: Name (35 to 38) "any" -7: Type { name: NodeId(6), args: None, optional: false } (35 to 38) -8: String (41 to 47) ""spam"" -9: Let { variable_name: NodeId(5), ty: Some(NodeId(7)), initializer: NodeId(8), is_mutable: false } (28 to 47) -10: Variable (60 to 61) "z" +7: Type(Ref { name: NodeId(6), args: None, optional: false }) (35 to 38) +8: Expr(String) (41 to 47) ""spam"" +9: Stmt(Let { variable_name: NodeId(5), ty: Some(NodeId(7)), initializer: NodeId(8), is_mutable: false }) (28 to 47) +10: VarDecl (60 to 61) "z" 11: Name (63 to 69) "string" -12: Type { name: NodeId(11), args: None, optional: false } (63 to 69) -13: Int (72 to 75) "123" -14: Let { variable_name: NodeId(10), ty: Some(NodeId(12)), initializer: NodeId(13), is_mutable: false } (56 to 75) -15: Variable (91 to 92) "w" +12: Type(Ref { name: NodeId(11), args: None, optional: false }) (63 to 69) +13: Expr(Int) (72 to 75) "123" +14: Stmt(Let { variable_name: NodeId(10), ty: Some(NodeId(12)), initializer: NodeId(13), is_mutable: false }) (56 to 75) +15: VarDecl (91 to 92) "w" 16: Name (94 to 98) "list" 17: Name (99 to 103) "list" 18: Name (104 to 107) "int" -19: Type { name: NodeId(18), args: None, optional: false } (104 to 107) +19: Type(Ref { name: NodeId(18), args: None, optional: false }) (104 to 107) 20: TypeArgs([NodeId(19)]) (103 to 108) -21: Type { name: NodeId(17), args: Some(NodeId(20)), optional: false } (99 to 103) +21: Type(Ref { name: NodeId(17), args: Some(NodeId(20)), optional: false }) (99 to 103) 22: TypeArgs([NodeId(21)]) (98 to 109) -23: Type { name: NodeId(16), args: Some(NodeId(22)), optional: false } (94 to 98) -24: String (116 to 119) "'a'" -25: List([NodeId(24)]) (114 to 120) -26: List([NodeId(25)]) (112 to 122) -27: Let { variable_name: NodeId(15), ty: Some(NodeId(23)), initializer: NodeId(26), is_mutable: false } (87 to 122) -28: Variable (128 to 129) "v" +23: Type(Ref { name: NodeId(16), args: Some(NodeId(22)), optional: false }) (94 to 98) +24: Expr(String) (116 to 119) "'a'" +25: Expr(List([NodeId(24)])) (114 to 120) +26: Expr(List([NodeId(25)])) (112 to 122) +27: Stmt(Let { variable_name: NodeId(15), ty: Some(NodeId(23)), initializer: NodeId(26), is_mutable: false }) (87 to 122) +28: VarDecl (128 to 129) "v" 29: Name (131 to 137) "record" 30: Name (138 to 139) "a" 31: Name (141 to 144) "int" -32: Type { name: NodeId(31), args: None, optional: false } (141 to 144) +32: Type(Ref { name: NodeId(31), args: None, optional: false }) (141 to 144) 33: Param { name: NodeId(30), ty: Some(NodeId(32)) } (138 to 144) 34: Params([NodeId(33)]) (137 to 145) -35: RecordType { fields: NodeId(34), optional: false } (131 to 146) -36: String (149 to 150) "a" -37: String (152 to 157) ""foo"" -38: Record { pairs: [(NodeId(36), NodeId(37))] } (148 to 158) -39: Let { variable_name: NodeId(28), ty: Some(NodeId(35)), initializer: NodeId(38), is_mutable: false } (124 to 158) -40: Block(BlockId(0)) (0 to 159) +35: Type(Record { fields: NodeId(34), optional: false }) (131 to 146) +36: Expr(String) (149 to 150) "a" +37: Expr(String) (152 to 157) ""foo"" +38: Expr(Record { pairs: [(NodeId(36), NodeId(37))] }) (148 to 158) +39: Stmt(Let { variable_name: NodeId(28), ty: Some(NodeId(35)), initializer: NodeId(38), is_mutable: false }) (124 to 158) +40: Expr(Block(BlockId(0))) (0 to 159) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(40) variables: [ v: NodeId(28), w: NodeId(15), x: NodeId(0), y: NodeId(5), z: NodeId(10) ] @@ -91,11 +91,11 @@ input_file: tests/let_mismatch.nu 39: () 40: () ==== TYPE ERRORS ==== -Error (NodeId 13): initializer does not match declared type -Error (NodeId 26): initializer does not match declared type -Error (NodeId 38): initializer does not match declared type +Error (NodeId 13): Expected string, got int +Error (NodeId 26): Expected list>, got list> +Error (NodeId 38): Expected record, got record ==== IR ==== register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 4): node Let { variable_name: NodeId(0), ty: Some(NodeId(2)), initializer: NodeId(3), is_mutable: false } not suported yet +Error (NodeId 4): node Stmt(Let { variable_name: NodeId(0), ty: Some(NodeId(2)), initializer: NodeId(3), is_mutable: false }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@list.nu.snap b/src/snapshots/new_nu_parser__test__node_output@list.nu.snap index fa681ca..7d17fca 100644 --- a/src/snapshots/new_nu_parser__test__node_output@list.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@list.nu.snap @@ -2,30 +2,29 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/list.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Int (1 to 2) "1" -1: Int (4 to 5) "2" -2: Int (7 to 8) "3" -3: List([NodeId(0), NodeId(1), NodeId(2)]) (0 to 8) -4: Int (11 to 12) "0" -5: Int (13 to 14) "1" -6: Int (15 to 16) "2" -7: List([NodeId(4), NodeId(5), NodeId(6)]) (10 to 16) -8: String (19 to 22) ""0"" -9: String (23 to 26) ""1"" -10: String (27 to 30) ""2"" -11: List([NodeId(8), NodeId(9), NodeId(10)]) (18 to 30) -12: Int (33 to 34) "0" -13: Int (35 to 36) "1" -14: Float (37 to 40) "2.2" -15: List([NodeId(12), NodeId(13), NodeId(14)]) (32 to 40) -16: Int (43 to 44) "0" -17: Int (45 to 46) "1" -18: String (47 to 50) ""2"" -19: List([NodeId(16), NodeId(17), NodeId(18)]) (42 to 50) -20: Block(BlockId(0)) (0 to 52) +0: Expr(Int) (1 to 2) "1" +1: Expr(Int) (4 to 5) "2" +2: Expr(Int) (7 to 8) "3" +3: Expr(List([NodeId(0), NodeId(1), NodeId(2)])) (0 to 8) +4: Expr(Int) (11 to 12) "0" +5: Expr(Int) (13 to 14) "1" +6: Expr(Int) (15 to 16) "2" +7: Expr(List([NodeId(4), NodeId(5), NodeId(6)])) (10 to 16) +8: Expr(String) (19 to 22) ""0"" +9: Expr(String) (23 to 26) ""1"" +10: Expr(String) (27 to 30) ""2"" +11: Expr(List([NodeId(8), NodeId(9), NodeId(10)])) (18 to 30) +12: Expr(Int) (33 to 34) "0" +13: Expr(Int) (35 to 36) "1" +14: Expr(Float) (37 to 40) "2.2" +15: Expr(List([NodeId(12), NodeId(13), NodeId(14)])) (32 to 40) +16: Expr(Int) (43 to 44) "0" +17: Expr(Int) (45 to 46) "1" +18: Expr(String) (47 to 50) ""2"" +19: Expr(List([NodeId(16), NodeId(17), NodeId(18)])) (42 to 50) +20: Expr(Block(BlockId(0))) (0 to 52) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(20) (empty) ==== TYPES ==== @@ -54,4 +53,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 3): node List([NodeId(0), NodeId(1), NodeId(2)]) not suported yet +Error (NodeId 3): node Expr(List([NodeId(0), NodeId(1), NodeId(2)])) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@literals.nu.snap b/src/snapshots/new_nu_parser__test__node_output@literals.nu.snap index db77463..6535d93 100644 --- a/src/snapshots/new_nu_parser__test__node_output@literals.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@literals.nu.snap @@ -2,16 +2,15 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/literals.nu -snapshot_kind: text --- ==== COMPILER ==== -0: True (1 to 5) -1: Null (6 to 10) -2: Int (11 to 12) "1" -3: String (13 to 16) "abc" -4: String (17 to 22) ""foo"" -5: List([NodeId(0), NodeId(1), NodeId(2), NodeId(3), NodeId(4)]) (0 to 22) -6: Block(BlockId(0)) (0 to 24) +0: Expr(True) (1 to 5) +1: Expr(Null) (6 to 10) +2: Expr(Int) (11 to 12) "1" +3: Expr(String) (13 to 16) "abc" +4: Expr(String) (17 to 22) ""foo"" +5: Expr(List([NodeId(0), NodeId(1), NodeId(2), NodeId(3), NodeId(4)])) (0 to 22) +6: Expr(Block(BlockId(0))) (0 to 24) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(6) (empty) ==== TYPES ==== @@ -26,4 +25,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 5): node List([NodeId(0), NodeId(1), NodeId(2), NodeId(3), NodeId(4)]) not suported yet +Error (NodeId 5): node Expr(List([NodeId(0), NodeId(1), NodeId(2), NodeId(3), NodeId(4)])) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@loop.nu.snap b/src/snapshots/new_nu_parser__test__node_output@loop.nu.snap index 8b4fb48..f53af03 100644 --- a/src/snapshots/new_nu_parser__test__node_output@loop.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@loop.nu.snap @@ -2,26 +2,25 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/loop.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Variable (4 to 5) "x" -1: Int (8 to 9) "0" -2: Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true } (0 to 9) -3: Variable (24 to 26) "$x" +0: VarDecl (4 to 5) "x" +1: Expr(Int) (8 to 9) "0" +2: Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true }) (0 to 9) +3: Expr(VarRef) (24 to 26) "$x" 4: GreaterThan (27 to 28) -5: Int (29 to 31) "10" -6: BinaryOp { lhs: NodeId(3), op: NodeId(4), rhs: NodeId(5) } (24 to 31) -7: Break (42 to 47) -8: Block(BlockId(0)) (32 to 53) -9: If { condition: NodeId(6), then_block: NodeId(8), else_block: None } (21 to 53) -10: Variable (59 to 61) "$x" +5: Expr(Int) (29 to 31) "10" +6: Expr(BinaryOp { lhs: NodeId(3), op: NodeId(4), rhs: NodeId(5) }) (24 to 31) +7: Stmt(Break) (42 to 47) +8: Expr(Block(BlockId(0))) (32 to 53) +9: Expr(If { condition: NodeId(6), then_block: NodeId(8), else_block: None }) (21 to 53) +10: Expr(VarRef) (59 to 61) "$x" 11: AddAssignment (62 to 64) -12: Int (65 to 66) "1" -13: BinaryOp { lhs: NodeId(10), op: NodeId(11), rhs: NodeId(12) } (59 to 66) -14: Block(BlockId(1)) (15 to 68) -15: Loop { block: NodeId(14) } (10 to 68) -16: Block(BlockId(2)) (0 to 68) +12: Expr(Int) (65 to 66) "1" +13: Expr(BinaryOp { lhs: NodeId(10), op: NodeId(11), rhs: NodeId(12) }) (59 to 66) +14: Expr(Block(BlockId(1))) (15 to 68) +15: Stmt(Loop { block: NodeId(14) }) (10 to 68) +16: Expr(Block(BlockId(2))) (0 to 68) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(16) variables: [ x: NodeId(0) ] @@ -44,11 +43,11 @@ snapshot_kind: text 13: unknown 14: unknown 15: unknown -16: unknown +16: () ==== TYPE ERRORS ==== -Error (NodeId 15): unsupported ast node 'Loop { block: NodeId(14) }' in typechecker +Error (NodeId 15): unsupported ast node 'Stmt(Loop { block: NodeId(14) })' in typechecker ==== IR ==== register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 2): node Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true } not suported yet +Error (NodeId 2): node Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@match.nu.snap b/src/snapshots/new_nu_parser__test__node_output@match.nu.snap index 05cb6ac..c1dfc68 100644 --- a/src/snapshots/new_nu_parser__test__node_output@match.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@match.nu.snap @@ -2,32 +2,31 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/match.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Variable (4 to 5) "x" -1: Int (8 to 9) "1" -2: Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: false } (0 to 9) -3: Variable (15 to 18) "foo" -4: Variable (27 to 29) "$x" -5: Int (34 to 35) "1" -6: String (39 to 44) ""one"" -7: Int (48 to 49) "2" -8: Variable (63 to 64) "w" -9: Int (67 to 68) "3" -10: Let { variable_name: NodeId(8), ty: None, initializer: NodeId(9), is_mutable: false } (59 to 68) -11: Int (73 to 74) "2" +0: VarDecl (4 to 5) "x" +1: Expr(Int) (8 to 9) "1" +2: Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: false }) (0 to 9) +3: VarDecl (15 to 18) "foo" +4: Expr(VarRef) (27 to 29) "$x" +5: Expr(Int) (34 to 35) "1" +6: Expr(String) (39 to 44) ""one"" +7: Expr(Int) (48 to 49) "2" +8: VarDecl (63 to 64) "w" +9: Expr(Int) (67 to 68) "3" +10: Stmt(Let { variable_name: NodeId(8), ty: None, initializer: NodeId(9), is_mutable: false }) (59 to 68) +11: Expr(Int) (73 to 74) "2" 12: Plus (75 to 76) -13: Variable (77 to 79) "$w" -14: BinaryOp { lhs: NodeId(11), op: NodeId(12), rhs: NodeId(13) } (73 to 79) -15: Block(BlockId(0)) (59 to 82) -16: Closure { params: None, block: NodeId(15) } (53 to 83) -17: Int (87 to 88) "3" -18: Null (92 to 96) -19: String (100 to 101) "_" +13: Expr(VarRef) (77 to 79) "$w" +14: Expr(BinaryOp { lhs: NodeId(11), op: NodeId(12), rhs: NodeId(13) }) (73 to 79) +15: Expr(Block(BlockId(0))) (59 to 82) +16: Expr(Closure { params: None, block: NodeId(15) }) (53 to 83) +17: Expr(Int) (87 to 88) "3" +18: Expr(Null) (92 to 96) +19: Expr(String) (100 to 101) "_" 20: Garbage (106 to 107) -21: Match { target: NodeId(4), match_arms: [(NodeId(5), NodeId(6)), (NodeId(7), NodeId(16)), (NodeId(17), NodeId(18)), (NodeId(19), NodeId(20))] } (21 to 110) -22: Let { variable_name: NodeId(3), ty: None, initializer: NodeId(21), is_mutable: false } (11 to 110) -23: Block(BlockId(1)) (0 to 111) +21: Expr(Match { target: NodeId(4), match_arms: [(NodeId(5), NodeId(6)), (NodeId(7), NodeId(16)), (NodeId(17), NodeId(18)), (NodeId(19), NodeId(20))] }) (21 to 110) +22: Stmt(Let { variable_name: NodeId(3), ty: None, initializer: NodeId(21), is_mutable: false }) (11 to 110) +23: Expr(Block(BlockId(1))) (0 to 111) ==== COMPILER ERRORS ==== Error (NodeId 20): use null instead of () diff --git a/src/snapshots/new_nu_parser__test__node_output@math.nu.snap b/src/snapshots/new_nu_parser__test__node_output@math.nu.snap index dc8f2ae..d64cb40 100644 --- a/src/snapshots/new_nu_parser__test__node_output@math.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@math.nu.snap @@ -2,14 +2,13 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/math.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Int (0 to 1) "3" +0: Expr(Int) (0 to 1) "3" 1: Plus (2 to 3) -2: Int (4 to 5) "4" -3: BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) } (0 to 5) -4: Block(BlockId(0)) (0 to 5) +2: Expr(Int) (4 to 5) "4" +3: Expr(BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) }) (0 to 5) +4: Expr(Block(BlockId(0))) (0 to 5) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(4) (empty) ==== TYPES ==== diff --git a/src/snapshots/new_nu_parser__test__node_output@math_precedence.nu.snap b/src/snapshots/new_nu_parser__test__node_output@math_precedence.nu.snap index 01dc14b..a63e639 100644 --- a/src/snapshots/new_nu_parser__test__node_output@math_precedence.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@math_precedence.nu.snap @@ -2,20 +2,19 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/math_precedence.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Int (0 to 1) "1" +0: Expr(Int) (0 to 1) "1" 1: Plus (2 to 3) -2: Int (4 to 5) "2" +2: Expr(Int) (4 to 5) "2" 3: Multiply (6 to 7) -4: Int (8 to 9) "3" +4: Expr(Int) (8 to 9) "3" 5: Plus (10 to 11) -6: Int (12 to 13) "4" -7: BinaryOp { lhs: NodeId(2), op: NodeId(3), rhs: NodeId(4) } (4 to 9) -8: BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(7) } (0 to 9) -9: BinaryOp { lhs: NodeId(8), op: NodeId(5), rhs: NodeId(6) } (0 to 13) -10: Block(BlockId(0)) (0 to 13) +6: Expr(Int) (12 to 13) "4" +7: Expr(BinaryOp { lhs: NodeId(2), op: NodeId(3), rhs: NodeId(4) }) (4 to 9) +8: Expr(BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(7) }) (0 to 9) +9: Expr(BinaryOp { lhs: NodeId(8), op: NodeId(5), rhs: NodeId(6) }) (0 to 13) +10: Expr(Block(BlockId(0))) (0 to 13) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(10) (empty) ==== TYPES ==== diff --git a/src/snapshots/new_nu_parser__test__node_output@mut_.nu.snap b/src/snapshots/new_nu_parser__test__node_output@mut_.nu.snap index a366991..17ac24f 100644 --- a/src/snapshots/new_nu_parser__test__node_output@mut_.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@mut_.nu.snap @@ -4,19 +4,19 @@ expression: evaluate_example(path) input_file: tests/mut_.nu --- ==== COMPILER ==== -0: Variable (4 to 5) "x" +0: VarDecl (4 to 5) "x" 1: Name (7 to 10) "int" -2: Type { name: NodeId(1), args: None, optional: false } (7 to 10) -3: Int (13 to 16) "123" -4: Let { variable_name: NodeId(0), ty: Some(NodeId(2)), initializer: NodeId(3), is_mutable: true } (0 to 16) -5: Variable (18 to 20) "$x" +2: Type(Ref { name: NodeId(1), args: None, optional: false }) (7 to 10) +3: Expr(Int) (13 to 16) "123" +4: Stmt(Let { variable_name: NodeId(0), ty: Some(NodeId(2)), initializer: NodeId(3), is_mutable: true }) (0 to 16) +5: Expr(VarRef) (18 to 20) "$x" 6: Assignment (21 to 22) -7: Int (23 to 24) "3" +7: Expr(Int) (23 to 24) "3" 8: Plus (25 to 26) -9: Int (27 to 30) "456" -10: BinaryOp { lhs: NodeId(7), op: NodeId(8), rhs: NodeId(9) } (23 to 30) -11: BinaryOp { lhs: NodeId(5), op: NodeId(6), rhs: NodeId(10) } (18 to 30) -12: Block(BlockId(0)) (0 to 30) +9: Expr(Int) (27 to 30) "456" +10: Expr(BinaryOp { lhs: NodeId(7), op: NodeId(8), rhs: NodeId(9) }) (23 to 30) +11: Expr(BinaryOp { lhs: NodeId(5), op: NodeId(6), rhs: NodeId(10) }) (18 to 30) +12: Expr(Block(BlockId(0))) (0 to 30) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(12) variables: [ x: NodeId(0) ] @@ -38,4 +38,4 @@ input_file: tests/mut_.nu register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 4): node Let { variable_name: NodeId(0), ty: Some(NodeId(2)), initializer: NodeId(3), is_mutable: true } not suported yet +Error (NodeId 4): node Stmt(Let { variable_name: NodeId(0), ty: Some(NodeId(2)), initializer: NodeId(3), is_mutable: true }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@record.nu.snap b/src/snapshots/new_nu_parser__test__node_output@record.nu.snap index fbca628..70f9561 100644 --- a/src/snapshots/new_nu_parser__test__node_output@record.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@record.nu.snap @@ -2,15 +2,14 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/record.nu -snapshot_kind: text --- ==== COMPILER ==== -0: String (1 to 2) "a" -1: Int (4 to 5) "1" -2: String (7 to 8) "b" -3: Int (10 to 11) "2" -4: Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(3))] } (0 to 12) -5: Block(BlockId(0)) (0 to 13) +0: Expr(String) (1 to 2) "a" +1: Expr(Int) (4 to 5) "1" +2: Expr(String) (7 to 8) "b" +3: Expr(Int) (10 to 11) "2" +4: Expr(Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(3))] }) (0 to 12) +5: Expr(Block(BlockId(0))) (0 to 13) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(5) (empty) ==== TYPES ==== @@ -24,4 +23,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 4): node Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(3))] } not suported yet +Error (NodeId 4): node Expr(Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(3))] }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@record2.nu.snap b/src/snapshots/new_nu_parser__test__node_output@record2.nu.snap index 33f7d3c..9f9d11e 100644 --- a/src/snapshots/new_nu_parser__test__node_output@record2.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@record2.nu.snap @@ -2,15 +2,14 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/record2.nu -snapshot_kind: text --- ==== COMPILER ==== -0: String (1 to 4) ""a"" -1: Int (6 to 7) "1" -2: String (9 to 12) ""b"" -3: Int (14 to 15) "2" -4: Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(3))] } (0 to 16) -5: Block(BlockId(0)) (0 to 17) +0: Expr(String) (1 to 4) ""a"" +1: Expr(Int) (6 to 7) "1" +2: Expr(String) (9 to 12) ""b"" +3: Expr(Int) (14 to 15) "2" +4: Expr(Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(3))] }) (0 to 16) +5: Expr(Block(BlockId(0))) (0 to 17) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(5) (empty) ==== TYPES ==== @@ -24,4 +23,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 4): node Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(3))] } not suported yet +Error (NodeId 4): node Expr(Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(3))] }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@record3.nu.snap b/src/snapshots/new_nu_parser__test__node_output@record3.nu.snap index 3792028..873b11e 100644 --- a/src/snapshots/new_nu_parser__test__node_output@record3.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@record3.nu.snap @@ -2,15 +2,14 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/record3.nu -snapshot_kind: text --- ==== COMPILER ==== -0: String (2 to 3) "a" -1: Int (5 to 6) "1" -2: String (9 to 10) "b" -3: Int (12 to 13) "2" -4: Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(3))] } (0 to 16) -5: Block(BlockId(0)) (0 to 17) +0: Expr(String) (2 to 3) "a" +1: Expr(Int) (5 to 6) "1" +2: Expr(String) (9 to 10) "b" +3: Expr(Int) (12 to 13) "2" +4: Expr(Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(3))] }) (0 to 16) +5: Expr(Block(BlockId(0))) (0 to 17) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(5) (empty) ==== TYPES ==== @@ -24,4 +23,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 4): node Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(3))] } not suported yet +Error (NodeId 4): node Expr(Record { pairs: [(NodeId(0), NodeId(1)), (NodeId(2), NodeId(3))] }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@reparse.nu.snap b/src/snapshots/new_nu_parser__test__node_output@reparse.nu.snap index d5a1a74..dc79f4c 100644 --- a/src/snapshots/new_nu_parser__test__node_output@reparse.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@reparse.nu.snap @@ -2,23 +2,22 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/reparse.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Variable (4 to 5) "x" +0: VarDecl (4 to 5) "x" 1: Name (10 to 11) "a" 2: Param { name: NodeId(1), ty: None } (10 to 11) 3: Params([NodeId(2)]) (9 to 12) -4: Variable (13 to 15) "$a" -5: Block(BlockId(0)) (13 to 16) -6: Closure { params: Some(NodeId(3)), block: NodeId(5) } (8 to 17) -7: Let { variable_name: NodeId(0), ty: None, initializer: NodeId(6), is_mutable: false } (0 to 17) -8: Variable (22 to 23) "y" -9: String (28 to 29) "a" -10: String (31 to 32) "b" -11: Record { pairs: [(NodeId(9), NodeId(10))] } (26 to 34) -12: Let { variable_name: NodeId(8), ty: None, initializer: NodeId(11), is_mutable: false } (18 to 34) -13: Block(BlockId(1)) (0 to 34) +4: Expr(VarRef) (13 to 15) "$a" +5: Expr(Block(BlockId(0))) (13 to 16) +6: Expr(Closure { params: Some(NodeId(3)), block: NodeId(5) }) (8 to 17) +7: Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(6), is_mutable: false }) (0 to 17) +8: VarDecl (22 to 23) "y" +9: Expr(String) (28 to 29) "a" +10: Expr(String) (31 to 32) "b" +11: Expr(Record { pairs: [(NodeId(9), NodeId(10))] }) (26 to 34) +12: Stmt(Let { variable_name: NodeId(8), ty: None, initializer: NodeId(11), is_mutable: false }) (18 to 34) +13: Expr(Block(BlockId(1))) (0 to 34) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(13) variables: [ x: NodeId(0), y: NodeId(8) ] @@ -43,4 +42,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 7): node Let { variable_name: NodeId(0), ty: None, initializer: NodeId(6), is_mutable: false } not suported yet +Error (NodeId 7): node Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(6), is_mutable: false }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@string.nu.snap b/src/snapshots/new_nu_parser__test__node_output@string.nu.snap index 79654e4..2e4dc94 100644 --- a/src/snapshots/new_nu_parser__test__node_output@string.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@string.nu.snap @@ -2,12 +2,11 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/string.nu -snapshot_kind: text --- ==== COMPILER ==== -0: String (0 to 13) ""hello world"" -1: String (14 to 27) "'hello world'" -2: Block(BlockId(0)) (0 to 27) +0: Expr(String) (0 to 13) ""hello world"" +1: Expr(String) (14 to 27) "'hello world'" +2: Expr(Block(BlockId(0))) (0 to 27) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(2) (empty) ==== TYPES ==== @@ -18,4 +17,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 0): node String not suported yet +Error (NodeId 0): node Expr(String) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@string_operation.nu.snap b/src/snapshots/new_nu_parser__test__node_output@string_operation.nu.snap index ccd1f2b..968e1a1 100644 --- a/src/snapshots/new_nu_parser__test__node_output@string_operation.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@string_operation.nu.snap @@ -2,14 +2,13 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/string_operation.nu -snapshot_kind: text --- ==== COMPILER ==== -0: String (0 to 5) ""abc"" +0: Expr(String) (0 to 5) ""abc"" 1: Plus (6 to 7) -2: String (8 to 13) ""def"" -3: BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) } (0 to 13) -4: Block(BlockId(0)) (0 to 13) +2: Expr(String) (8 to 13) ""def"" +3: Expr(BinaryOp { lhs: NodeId(0), op: NodeId(1), rhs: NodeId(2) }) (0 to 13) +4: Expr(Block(BlockId(0))) (0 to 13) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(4) (empty) ==== TYPES ==== @@ -22,4 +21,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 0): node String not suported yet +Error (NodeId 0): node Expr(String) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@table.nu.snap b/src/snapshots/new_nu_parser__test__node_output@table.nu.snap index 9cc85a8..46ec8b8 100644 --- a/src/snapshots/new_nu_parser__test__node_output@table.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@table.nu.snap @@ -2,20 +2,19 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/table.nu -snapshot_kind: text --- ==== COMPILER ==== -0: String (7 to 10) ""a"" -1: String (12 to 15) ""b"" -2: List([NodeId(0), NodeId(1)]) (6 to 15) -3: Int (24 to 25) "1" -4: Int (27 to 28) "2" -5: List([NodeId(3), NodeId(4)]) (23 to 28) -6: Int (35 to 36) "3" -7: Int (38 to 39) "4" -8: List([NodeId(6), NodeId(7)]) (34 to 39) -9: Table { header: NodeId(2), rows: [NodeId(5), NodeId(8)] } (0 to 41) -10: Block(BlockId(0)) (0 to 42) +0: Expr(String) (7 to 10) ""a"" +1: Expr(String) (12 to 15) ""b"" +2: Expr(List([NodeId(0), NodeId(1)])) (6 to 15) +3: Expr(Int) (24 to 25) "1" +4: Expr(Int) (27 to 28) "2" +5: Expr(List([NodeId(3), NodeId(4)])) (23 to 28) +6: Expr(Int) (35 to 36) "3" +7: Expr(Int) (38 to 39) "4" +8: Expr(List([NodeId(6), NodeId(7)])) (34 to 39) +9: Expr(Table { header: NodeId(2), rows: [NodeId(5), NodeId(8)] }) (0 to 41) +10: Expr(Block(BlockId(0))) (0 to 42) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(10) (empty) ==== TYPES ==== @@ -31,9 +30,9 @@ snapshot_kind: text 9: unknown 10: unknown ==== TYPE ERRORS ==== -Error (NodeId 9): unsupported ast node 'Table { header: NodeId(2), rows: [NodeId(5), NodeId(8)] }' in typechecker +Error (NodeId 9): unsupported ast node 'Expr(Table { header: NodeId(2), rows: [NodeId(5), NodeId(8)] })' in typechecker ==== IR ==== register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 9): node Table { header: NodeId(2), rows: [NodeId(5), NodeId(8)] } not suported yet +Error (NodeId 9): node Expr(Table { header: NodeId(2), rows: [NodeId(5), NodeId(8)] }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@table2.nu.snap b/src/snapshots/new_nu_parser__test__node_output@table2.nu.snap index 46ed72c..bbd39b5 100644 --- a/src/snapshots/new_nu_parser__test__node_output@table2.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@table2.nu.snap @@ -2,20 +2,19 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/table2.nu -snapshot_kind: text --- ==== COMPILER ==== -0: String (7 to 8) "a" -1: String (10 to 11) "b" -2: List([NodeId(0), NodeId(1)]) (6 to 11) -3: Int (20 to 21) "1" -4: Int (23 to 24) "2" -5: List([NodeId(3), NodeId(4)]) (19 to 24) -6: Int (31 to 32) "3" -7: Int (34 to 35) "4" -8: List([NodeId(6), NodeId(7)]) (30 to 35) -9: Table { header: NodeId(2), rows: [NodeId(5), NodeId(8)] } (0 to 37) -10: Block(BlockId(0)) (0 to 38) +0: Expr(String) (7 to 8) "a" +1: Expr(String) (10 to 11) "b" +2: Expr(List([NodeId(0), NodeId(1)])) (6 to 11) +3: Expr(Int) (20 to 21) "1" +4: Expr(Int) (23 to 24) "2" +5: Expr(List([NodeId(3), NodeId(4)])) (19 to 24) +6: Expr(Int) (31 to 32) "3" +7: Expr(Int) (34 to 35) "4" +8: Expr(List([NodeId(6), NodeId(7)])) (30 to 35) +9: Expr(Table { header: NodeId(2), rows: [NodeId(5), NodeId(8)] }) (0 to 37) +10: Expr(Block(BlockId(0))) (0 to 38) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(10) (empty) ==== TYPES ==== @@ -31,9 +30,9 @@ snapshot_kind: text 9: unknown 10: unknown ==== TYPE ERRORS ==== -Error (NodeId 9): unsupported ast node 'Table { header: NodeId(2), rows: [NodeId(5), NodeId(8)] }' in typechecker +Error (NodeId 9): unsupported ast node 'Expr(Table { header: NodeId(2), rows: [NodeId(5), NodeId(8)] })' in typechecker ==== IR ==== register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 9): node Table { header: NodeId(2), rows: [NodeId(5), NodeId(8)] } not suported yet +Error (NodeId 9): node Expr(Table { header: NodeId(2), rows: [NodeId(5), NodeId(8)] }) not suported yet diff --git a/src/snapshots/new_nu_parser__test__node_output@variable_names.nu.snap b/src/snapshots/new_nu_parser__test__node_output@variable_names.nu.snap index ecd843c..0225df8 100644 --- a/src/snapshots/new_nu_parser__test__node_output@variable_names.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@variable_names.nu.snap @@ -2,13 +2,12 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/variable_names.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Variable (0 to 4) "$abc" -1: Variable (5 to 7) "$_" -2: Variable (8 to 12) "$a_c" +0: Expr(VarRef) (0 to 4) "$abc" +1: Expr(VarRef) (5 to 7) "$_" +2: Expr(VarRef) (8 to 12) "$a_c" 3: Garbage (14 to 17) -4: Block(BlockId(0)) (0 to 18) +4: Expr(Block(BlockId(0))) (0 to 18) ==== COMPILER ERRORS ==== Error (NodeId 3): variable name must be a bareword diff --git a/src/snapshots/new_nu_parser__test__node_output@while.nu.snap b/src/snapshots/new_nu_parser__test__node_output@while.nu.snap index f3cc1b8..7bd834c 100644 --- a/src/snapshots/new_nu_parser__test__node_output@while.nu.snap +++ b/src/snapshots/new_nu_parser__test__node_output@while.nu.snap @@ -2,23 +2,22 @@ source: src/test.rs expression: evaluate_example(path) input_file: tests/while.nu -snapshot_kind: text --- ==== COMPILER ==== -0: Variable (4 to 5) "x" -1: Int (8 to 9) "0" -2: Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true } (0 to 9) -3: Int (16 to 17) "1" +0: VarDecl (4 to 5) "x" +1: Expr(Int) (8 to 9) "0" +2: Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true }) (0 to 9) +3: Expr(Int) (16 to 17) "1" 4: LessThan (18 to 19) -5: Int (20 to 21) "2" -6: BinaryOp { lhs: NodeId(3), op: NodeId(4), rhs: NodeId(5) } (16 to 21) -7: Variable (26 to 28) "$x" +5: Expr(Int) (20 to 21) "2" +6: Expr(BinaryOp { lhs: NodeId(3), op: NodeId(4), rhs: NodeId(5) }) (16 to 21) +7: Expr(VarRef) (26 to 28) "$x" 8: AddAssignment (29 to 31) -9: Int (32 to 33) "1" -10: BinaryOp { lhs: NodeId(7), op: NodeId(8), rhs: NodeId(9) } (26 to 33) -11: Block(BlockId(0)) (22 to 35) -12: While { condition: NodeId(6), block: NodeId(11) } (10 to 35) -13: Block(BlockId(1)) (0 to 36) +9: Expr(Int) (32 to 33) "1" +10: Expr(BinaryOp { lhs: NodeId(7), op: NodeId(8), rhs: NodeId(9) }) (26 to 33) +11: Expr(Block(BlockId(0))) (22 to 35) +12: Stmt(While { condition: NodeId(6), block: NodeId(11) }) (10 to 35) +13: Expr(Block(BlockId(1))) (0 to 36) ==== SCOPE ==== 0: Frame Scope, node_id: NodeId(13) variables: [ x: NodeId(0) ] @@ -42,4 +41,4 @@ snapshot_kind: text register_count: 0 file_count: 0 ==== IR ERRORS ==== -Error (NodeId 2): node Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true } not suported yet +Error (NodeId 2): node Stmt(Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true }) not suported yet diff --git a/src/typechecker.rs b/src/typechecker.rs index 71077e8..38f8e3d 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -1,6 +1,7 @@ use crate::compiler::Compiler; use crate::errors::{Severity, SourceError}; -use crate::parser::{AstNode, NodeId}; +use crate::parser::{AstNode, BlockId, Expr, NodeId, Stmt, TypeAst}; +use crate::resolver::{TypeDecl, TypeDeclId}; use std::cmp::Ordering; use std::collections::HashSet; @@ -31,6 +32,7 @@ pub enum Type { /// output anything and thus don't have any type. None, Any, + Top, Number, Nothing, Int, @@ -43,6 +45,8 @@ pub enum Type { Stream(TypeId), Record(RecordTypeId), OneOf(OneOfId), + Ref(TypeDeclId), + ExVar(ExVarId), Error, } @@ -73,6 +77,10 @@ pub const CLOSURE_TYPE: TypeId = TypeId(11); pub const LIST_ANY_TYPE: TypeId = TypeId(12); pub const BYTE_STREAM_TYPE: TypeId = TypeId(13); pub const ERROR_TYPE: TypeId = TypeId(14); +pub const TOP_TYPE: TypeId = TypeId(15); + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ExVarId(pub usize); pub struct Typechecker<'a> { /// Immutable reference to a compiler after the name binding pass @@ -80,6 +88,8 @@ pub struct Typechecker<'a> { /// Types referenced by TypeId types: Vec, + /// Existential type variables referenced by ExVarId + ex_vars: Vec>, /// Types of nodes. Each type in this vector matches a node in compiler.ast_nodes at the same position. pub node_types: Vec, @@ -117,18 +127,14 @@ impl<'a> Typechecker<'a> { Type::List(ANY_TYPE), Type::Stream(BINARY_TYPE), Type::Error, + Type::Top, ], + ex_vars: Vec::new(), node_types: vec![UNKNOWN_TYPE; compiler.ast_nodes.len()], record_types: Vec::new(), oneof_types: Vec::new(), variable_types: vec![UNKNOWN_TYPE; compiler.variables.len()], - decl_types: vec![ - vec![InOutType { - in_type: ANY_TYPE, - out_type: ANY_TYPE, - }]; - compiler.decls.len() - ], + decl_types: vec![vec![]; compiler.decls.len()], errors: vec![], } } @@ -194,21 +200,10 @@ impl<'a> Typechecker<'a> { fn typecheck_node(&mut self, node_id: NodeId) { match self.compiler.ast_nodes[node_id.0] { - AstNode::Null => { - self.set_node_type_id(node_id, NOTHING_TYPE); - } - AstNode::Int => { - self.set_node_type_id(node_id, INT_TYPE); - } - AstNode::Float => { - self.set_node_type_id(node_id, FLOAT_TYPE); - } - AstNode::True | AstNode::False => { - self.set_node_type_id(node_id, BOOL_TYPE); - } - AstNode::String => { - self.set_node_type_id(node_id, STRING_TYPE); + AstNode::Expr(ref expr) => { + self.typecheck_expr(expr.clone(), node_id, UNKNOWN_TYPE); } + AstNode::Stmt(ref stmt) => self.typecheck_stmt(stmt.clone(), node_id), AstNode::Params(ref params) => { for param in params { self.typecheck_node(*param); @@ -218,7 +213,7 @@ impl<'a> Typechecker<'a> { } AstNode::Param { name, ty } => { if let Some(ty) = ty { - self.typecheck_node(ty); + self.typecheck_type(ty); let var_id = self .compiler @@ -231,52 +226,81 @@ impl<'a> Typechecker<'a> { self.set_node_type_id(node_id, ANY_TYPE); } } - AstNode::Type { - name, - args, - optional, - } => { - let ty_id = self.typecheck_type(name, args, optional); - self.set_node_type_id(node_id, ty_id); - } - AstNode::RecordType { - fields, - optional: _, // TODO handle optional record types - } => { - let AstNode::Params(field_nodes) = self.compiler.get_node(fields) else { - panic!("internal error: record fields aren't Params"); - }; - let mut fields = field_nodes - .iter() - .map(|field| { - let AstNode::Param { name, ty } = self.compiler.get_node(*field) else { - panic!("internal error: record field isn't Param"); - }; - let ty_id = match ty { - Some(ty) => { - self.typecheck_node(*ty); - self.type_id_of(*ty) - } - None => ANY_TYPE, - }; - (*name, ty_id) - }) - .collect::>(); - // Store fields sorted by name - fields.sort_by_cached_key(|(name, _)| self.compiler.get_span_contents(*name)); - - self.record_types.push(fields); - let ty_id = self.push_type(Type::Record(RecordTypeId(self.record_types.len() - 1))); - self.set_node_type_id(node_id, ty_id); - } AstNode::TypeArgs(ref args) => { for arg in args { - self.typecheck_node(*arg); + self.typecheck_type(*arg); } // Type argument lists are not supposed to be evaluated self.set_node_type_id(node_id, FORBIDDEN_TYPE); } - AstNode::List(ref items) => { + _ => self.error( + format!( + "unsupported ast node '{:?}' in typechecker", + self.compiler.ast_nodes[node_id.0] + ), + node_id, + ), + } + } + + fn typecheck_block(&mut self, block_id: BlockId, expected: TypeId) -> TypeId { + let block = &self.compiler.blocks[block_id.0]; + // Block type is the type of the last statement, since blocks + // by themselves aren't supposed to be typed + let mut block_type = NONE_TYPE; + + for inner_node_id in &block.nodes { + if let AstNode::Stmt(Stmt::Def { + name, + params, + in_out_types, + .. + }) = self.compiler.get_node(*inner_node_id) + { + self.add_def_signature(*name, *params, *in_out_types) + } + } + + for (i, inner_node_id) in block.nodes.iter().enumerate() { + match self.compiler.get_node(*inner_node_id) { + AstNode::Stmt(Stmt::Expr(expr_id)) => { + if i == block.nodes.len() - 1 { + block_type = self.typecheck_expr_id(*expr_id, expected); + } else { + self.typecheck_expr_id(*expr_id, TOP_TYPE); + } + } + AstNode::Expr(expr) => { + if i == block.nodes.len() - 1 { + block_type = self.typecheck_expr(expr.clone(), *inner_node_id, expected); + } else { + self.typecheck_expr(expr.clone(), *inner_node_id, TOP_TYPE); + } + } + AstNode::Stmt(stmt) => self.typecheck_stmt(stmt.clone(), *inner_node_id), + x => panic!("Internal error: block did not contain statement: {:?}", x), + } + } + + block_type + } + + fn typecheck_expr_id(&mut self, expr_id: NodeId, expected: TypeId) -> TypeId { + match self.compiler.get_node(expr_id) { + AstNode::Expr(ref expr) => self.typecheck_expr(expr.clone(), expr_id, expected), + _ => panic!("Internal error: Node {} is not an expression", expr_id.0), + } + } + + /// Infer a type for an expression and update self.types + fn typecheck_expr(&mut self, expr: Expr, node_id: NodeId, expected: TypeId) -> TypeId { + let type_id = match expr { + Expr::Null => NOTHING_TYPE, + Expr::Int => INT_TYPE, + Expr::Float => FLOAT_TYPE, + Expr::True | Expr::False => BOOL_TYPE, + Expr::String => STRING_TYPE, + Expr::List(ref items) => { if let Some(first_id) = items.first() { self.typecheck_node(*first_id); let first_type = self.type_of(*first_id); @@ -298,17 +322,18 @@ impl<'a> Typechecker<'a> { } if all_same { - self.set_node_type(node_id, Type::List(self.type_id_of(*first_id))); + self.push_type(Type::List(self.type_id_of(*first_id))) } else if all_numbers { - self.set_node_type(node_id, Type::List(NUMBER_TYPE)); + self.push_type(Type::List(NUMBER_TYPE)) } else { - self.set_node_type_id(node_id, LIST_ANY_TYPE); + LIST_ANY_TYPE } } else { - self.set_node_type_id(node_id, LIST_ANY_TYPE); + LIST_ANY_TYPE } } - AstNode::Record { ref pairs } => { + Expr::Block(block_id) => self.typecheck_block(block_id, expected), + Expr::Record { ref pairs } => { let mut field_types = pairs .iter() .map(|(name, value)| { @@ -319,99 +344,99 @@ impl<'a> Typechecker<'a> { field_types.sort_by_cached_key(|(name, _)| self.compiler.get_span_contents(*name)); self.record_types.push(field_types); - let ty_id = self.push_type(Type::Record(RecordTypeId(self.record_types.len() - 1))); - self.set_node_type_id(node_id, ty_id); - } - AstNode::Block(block_id) => { - let block = &self.compiler.blocks[block_id.0]; - - for inner_node_id in &block.nodes { - self.typecheck_node(*inner_node_id); - } - - // Block type is the type of the last statement, since blocks - // by themselves aren't supposed to be typed - let block_type = block - .nodes - .last() - .map_or(NONE_TYPE, |node_id| self.type_id_of(*node_id)); - - self.set_node_type_id(node_id, block_type); + self.push_type(Type::Record(RecordTypeId(self.record_types.len() - 1))) } - AstNode::Closure { params, block } => { + Expr::Closure { params, block } => { // TODO: input/output types if let Some(params_node_id) = params { self.typecheck_node(params_node_id); } self.typecheck_node(block); - self.set_node_type_id(node_id, CLOSURE_TYPE); + CLOSURE_TYPE } - AstNode::BinaryOp { lhs, op, rhs } => self.typecheck_binary_op(lhs, op, rhs, node_id), - AstNode::Let { - variable_name, - ty, - initializer, - is_mutable: _, - } => self.typecheck_let(variable_name, ty, initializer, node_id), - AstNode::Variable => { + Expr::BinaryOp { lhs, op, rhs } => self.typecheck_binary_op(lhs, op, rhs), + Expr::VarRef => { let var_id = self .compiler .var_resolution .get(&node_id) .expect("missing resolved variable"); - self.set_node_type_id(node_id, self.variable_types[var_id.0]); + self.variable_types[var_id.0] } - AstNode::If { + Expr::If { condition, then_block, else_block, } => { - self.typecheck_node(condition); - self.typecheck_node(then_block); + self.typecheck_expr_id(condition, BOOL_TYPE); - let then_type_id = self.type_id_of(then_block); - let mut else_type = None; + let then_type_id = self.typecheck_expr_id(then_block, expected); if let Some(else_blk) = else_block { - self.typecheck_node(else_blk); - else_type = Some(self.type_of(else_blk)); - } - - let mut types = HashSet::new(); - self.add_resolved_types(&mut types, &then_type_id); - - if let Some(Type::OneOf(id)) = else_type { - types.extend(self.oneof_types[id.0].iter()); - } else if else_type.is_none() { - types.insert(NONE_TYPE); + let else_type_id = self.typecheck_expr_id(else_blk, expected); + let mut types = HashSet::new(); + types.insert(then_type_id); + types.insert(else_type_id); + self.create_oneof(types) } else { - types.insert(self.type_id_of(else_block.expect("Already checked"))); + then_type_id } - - // the condition should always evaluate to a boolean - if self.type_of(condition) != Type::Bool { - self.error("The condition for if branch is not a boolean", condition); - self.set_node_type_id(node_id, ERROR_TYPE); - } else if types.len() > 1 { - self.oneof_types.push(types); - self.set_node_type(node_id, Type::OneOf(OneOfId(self.oneof_types.len() - 1))); + } + Expr::Call { ref parts } => self.typecheck_call(parts, node_id), + Expr::Match { + ref target, + ref match_arms, + } => { + // Check all the output types of match + let output_types = self.typecheck_match(target, match_arms); + if output_types.is_empty() { + NOTHING_TYPE } else { - self.set_node_type_id(node_id, *types.iter().next().expect("Can't be empty")); + self.create_oneof(output_types) } } - AstNode::Def { - name, - params, - in_out_types, - block, - } => self.typecheck_def(name, params, in_out_types, block, node_id), - AstNode::Alias { new_name, old_name } => { - self.typecheck_alias(new_name, old_name, node_id) + _ => { + self.error( + format!( + "unsupported ast node '{:?}' in typechecker", + self.compiler.ast_nodes[node_id.0] + ), + node_id, + ); + UNKNOWN_TYPE } - AstNode::Call { ref parts } => self.typecheck_call(parts, node_id), - AstNode::For { + }; + + let got = self.types[type_id.0]; + let exp = self.types[expected.0]; + if !self.is_subtype(got, exp) { + self.error( + format!( + "Expected {}, got {}", + self.type_to_string(expected), + self.type_to_string(type_id) + ), + node_id, + ); + } + + self.set_node_type_id(node_id, type_id); + type_id + } + + fn typecheck_stmt(&mut self, stmt: Stmt, node_id: NodeId) { + match stmt { + Stmt::Let { + variable_name, + ty, + initializer, + is_mutable: _, + } => self.typecheck_let(variable_name, ty, initializer, node_id), + Stmt::Def { name, block, .. } => self.typecheck_def(name, block, node_id), + Stmt::Alias { new_name, old_name } => self.typecheck_alias(new_name, old_name, node_id), + Stmt::For { variable, range, block, @@ -442,7 +467,7 @@ impl<'a> Typechecker<'a> { self.set_node_type_id(node_id, NONE_TYPE); } } - AstNode::While { condition, block } => { + Stmt::While { condition, block } => { self.typecheck_node(block); if self.type_id_of(block) != NONE_TYPE { self.error("Blocks in looping constructs cannot return values", block); @@ -458,34 +483,7 @@ impl<'a> Typechecker<'a> { self.set_node_type_id(node_id, self.type_id_of(block)); } } - AstNode::Match { - ref target, - ref match_arms, - } => { - // Check all the output types of match - let output_types = self.typecheck_match(target, match_arms); - match output_types.len().cmp(&1) { - Ordering::Greater => { - self.oneof_types.push(output_types); - self.set_node_type( - node_id, - Type::OneOf(OneOfId(self.oneof_types.len() - 1)), - ); - } - Ordering::Equal => { - self.set_node_type_id( - node_id, - *output_types - .iter() - .next() - .expect("Will contain one element"), - ); - } - Ordering::Less => { - self.set_node_type_id(node_id, NOTHING_TYPE); - } - } - } + Stmt::Expr(node) => self.typecheck_node(node), _ => self.error( format!( "unsupported ast node '{:?}' in typechecker", @@ -553,7 +551,7 @@ impl<'a> Typechecker<'a> { output_types } - fn typecheck_binary_op(&mut self, lhs: NodeId, op: NodeId, rhs: NodeId, node_id: NodeId) { + fn typecheck_binary_op(&mut self, lhs: NodeId, op: NodeId, rhs: NodeId) -> TypeId { self.typecheck_node(lhs); self.typecheck_node(rhs); self.set_node_type_id(op, FORBIDDEN_TYPE); @@ -675,20 +673,14 @@ impl<'a> Typechecker<'a> { }; if let Some(ty) = out_type { - self.set_node_type(node_id, ty); + self.push_type(ty) } else { - self.set_node_type_id(node_id, ERROR_TYPE); + ERROR_TYPE } } - fn typecheck_def( - &mut self, - name: NodeId, - params: NodeId, - in_out_types: Option, - block: NodeId, - node_id: NodeId, - ) { + fn add_def_signature(&mut self, name: NodeId, params: NodeId, in_out_types: Option) { + self.typecheck_node(params); let in_out_types = in_out_types .map(|ty| { let AstNode::InOutTypes(types) = self.compiler.get_node(ty) else { @@ -700,33 +692,28 @@ impl<'a> Typechecker<'a> { let AstNode::InOutType(in_ty, out_ty) = self.compiler.get_node(*ty) else { panic!("internal error: return type is not a return type"); }; - let AstNode::Type { - name: in_name, - args: in_args, - optional: in_optional, - } = *self.compiler.get_node(*in_ty) - else { - panic!("internal error: type is not a type"); - }; - let AstNode::Type { - name: out_name, - args: out_args, - optional: out_optional, - } = *self.compiler.get_node(*out_ty) - else { - panic!("internal error: type is not a type"); - }; InOutType { - in_type: self.typecheck_type(in_name, in_args, in_optional), - out_type: self.typecheck_type(out_name, out_args, out_optional), + in_type: self.typecheck_type(*in_ty), + out_type: self.typecheck_type(*out_ty), } }) .collect::>() }) .unwrap_or_default(); - self.typecheck_node(params); - self.typecheck_node(block); + // set input/output types for the command + let decl_id = self + .compiler + .decl_resolution + .get(&name) + .expect("missing declared decl"); + + if !in_out_types.is_empty() { + self.decl_types[decl_id.0] = in_out_types; + } + } + + fn typecheck_def(&mut self, name: NodeId, block: NodeId, node_id: NodeId) { self.set_node_type_id(node_id, NONE_TYPE); // set input/output types for the command @@ -736,14 +723,18 @@ impl<'a> Typechecker<'a> { .get(&name) .expect("missing declared decl"); + let in_out_types = &self.decl_types[decl_id.0]; if in_out_types.is_empty() { + let inferred = self.typecheck_expr_id(block, ANY_TYPE); self.decl_types[decl_id.0] = vec![InOutType { in_type: ANY_TYPE, - out_type: self.type_id_of(block), + out_type: inferred, }]; } else { - // TODO check that block output type matches expected type - self.decl_types[decl_id.0] = in_out_types; + // TODO this doesn't match each input type to its corresponding output type, + // just uses a union of all the output types as the expected type + let expected = self.create_oneof(in_out_types.iter().map(|io| io.out_type).collect()); + self.typecheck_expr_id(block, expected); } } @@ -768,24 +759,57 @@ impl<'a> Typechecker<'a> { ); } - fn typecheck_call(&mut self, parts: &[NodeId], node_id: NodeId) { - let num_name_parts = if let Some(decl_id) = self.compiler.decl_resolution.get(&node_id) { - // TODO: The type should be `oneof` - self.set_node_type_id(node_id, ANY_TYPE); + fn typecheck_call(&mut self, parts: &[NodeId], node_id: NodeId) -> TypeId { + if let Some(decl_id) = self.compiler.decl_resolution.get(&node_id) { + let num_name_parts = self.compiler.decls[decl_id.0].name().split(' ').count(); + let decl_node_id = self.compiler.decl_nodes[decl_id.0]; + let AstNode::Stmt(Stmt::Def { params, .. }) = self.compiler.get_node(decl_node_id) + else { + panic!("Internal error: Expected def") + }; + let AstNode::Params(params) = self.compiler.get_node(*params) else { + panic!("Internal error: Expected def") + }; + let num_args = parts.len() - num_name_parts; + if params.len() != num_args { + self.error( + format!("Expected {} argument(s), got {}", params.len(), num_args), + node_id, + ); + } - self.compiler.decls[decl_id.0].name().split(' ').count() + for (param, arg) in params.iter().zip(&parts[num_name_parts..]) { + let expected = self.type_id_of(*param); + if matches!(self.compiler.ast_nodes[arg.0], AstNode::Name) { + self.set_node_type_id(*arg, STRING_TYPE); + if !self.is_subtype(Type::String, self.types[expected.0]) { + self.error( + format!("Expected {}, got string", self.type_to_string(expected)), + *arg, + ); + } + } else { + self.typecheck_expr_id(*arg, expected); + } + } + + // TODO base this on pipeline input type + self.create_oneof( + self.decl_types[decl_id.0] + .iter() + .map(|io| io.out_type) + .collect(), + ) } else { // external call - self.node_types[node_id.0] = BYTE_STREAM_TYPE; - 1 - }; - - for part in &parts[num_name_parts..] { - if matches!(self.compiler.ast_nodes[part.0], AstNode::Name) { - self.set_node_type_id(*part, STRING_TYPE); - } else { - self.typecheck_node(*part); + for part in &parts[1..] { + if matches!(self.compiler.ast_nodes[part.0], AstNode::Name) { + self.set_node_type_id(*part, STRING_TYPE); + } else { + self.typecheck_node(*part); + } } + BYTE_STREAM_TYPE } } @@ -796,15 +820,13 @@ impl<'a> Typechecker<'a> { initializer: NodeId, node_id: NodeId, ) { - self.typecheck_node(initializer); - - if let Some(ty) = ty { - self.typecheck_node(ty); - - if !self.is_type_compatible(self.type_of(ty), self.type_of(initializer)) { - self.error("initializer does not match declared type", initializer) - } - } + let expected = if let Some(node_id) = ty { + self.typecheck_type(node_id) + } else { + ANY_TYPE + }; + let init_ty_id = self.typecheck_expr_id(initializer, expected); + let type_id = if ty.is_some() { expected } else { init_ty_id }; let var_id = self .compiler @@ -812,85 +834,116 @@ impl<'a> Typechecker<'a> { .get(&variable_name) .expect("missing declared variable"); - let type_id = if let Some(ty) = ty { - self.type_id_of(ty) - } else { - self.type_id_of(initializer) - }; - self.variable_types[var_id.0] = type_id; self.set_node_type_id(variable_name, type_id); self.set_node_type_id(node_id, NONE_TYPE); } - fn typecheck_type( - &mut self, - name_id: NodeId, - args_id: Option, - _optional: bool, - ) -> TypeId { - let name = self.compiler.get_span_contents(name_id); - - // taken from parse_shape_name() in Nushell: - match name { - b"any" => ANY_TYPE, - // b"binary" => SyntaxShape::Binary, - // b"block" => // not possible to pass blocks - b"list" => { - if let Some(args_id) = args_id { - self.typecheck_node(args_id); - - if let AstNode::TypeArgs(args) = self.compiler.get_node(args_id) { - if args.len() > 1 { - let types = - String::from_utf8_lossy(self.compiler.get_span_contents(args_id)); - self.error(format!("list must have only one type argument (to allow selection of types, use oneof{} -- WIP)", types), args_id); - self.push_type(Type::List(UNKNOWN_TYPE)) - } else if args.is_empty() { - self.error("list must have one type argument", args_id); - self.push_type(Type::List(UNKNOWN_TYPE)) + fn typecheck_type(&mut self, node_id: NodeId) -> TypeId { + let AstNode::Type(ty) = self.compiler.get_node(node_id) else { + panic!("internal error: Expected type"); + }; + let type_id = match ty { + TypeAst::Ref { + name: name_id, + args: args_id, + .. + } => { + let name = self.compiler.get_span_contents(*name_id); + + // taken from parse_shape_name() in Nushell: + match name { + b"any" => ANY_TYPE, + // b"binary" => SyntaxShape::Binary, + // b"block" => // not possible to pass blocks + b"list" => { + if let Some(args_id) = *args_id { + self.typecheck_node(args_id); + + if let AstNode::TypeArgs(args) = self.compiler.get_node(args_id) { + if args.len() > 1 { + let types = String::from_utf8_lossy( + self.compiler.get_span_contents(args_id), + ); + self.error(format!("list must have only one type argument (to allow selection of types, use oneof{} -- WIP)", types), args_id); + self.push_type(Type::List(UNKNOWN_TYPE)) + } else if args.is_empty() { + self.error("list must have one type argument", args_id); + self.push_type(Type::List(UNKNOWN_TYPE)) + } else { + let args_ty_id = self.type_id_of(args[0]); + self.push_type(Type::List(args_ty_id)) + } + } else { + panic!("args are not args"); + } } else { - let args_ty_id = self.type_id_of(args[0]); - self.push_type(Type::List(args_ty_id)) + LIST_ANY_TYPE + } + } + b"bool" => BOOL_TYPE, + // b"cell-path" => SyntaxShape::CellPath, + b"closure" => CLOSURE_TYPE, //FIXME: Closures should have known output types + // b"datetime" => SyntaxShape::DateTime, + // b"directory" => SyntaxShape::Directory, + // b"duration" => SyntaxShape::Duration, + // b"error" => SyntaxShape::Error, + b"float" => FLOAT_TYPE, + // b"filesize" => SyntaxShape::Filesize, + // b"glob" => SyntaxShape::GlobPattern, + b"int" => INT_TYPE, + // _ if bytes.starts_with(b"list") => parse_list_shape(working_set, bytes, span, use_loc), + b"nothing" => NOTHING_TYPE, + b"number" => NUMBER_TYPE, + // b"path" => SyntaxShape::Filepath, + // b"range" => SyntaxShape::Range, + // _ if bytes.starts_with(b"record") => { + // parse_collection_shape(working_set, bytes, span, use_loc) + // } + b"string" => STRING_TYPE, + // _ if bytes.starts_with(b"table") => { + // parse_collection_shape(working_set, bytes, span, use_loc) + // } + _ => { + // if bytes.contains(&b'@') { + // // type with completion + // } else { + // } + if let Some(ty_id) = self.compiler.type_resolution.get(name_id) { + self.push_type(Type::Ref(*ty_id)) + } else { + UNKNOWN_TYPE } - } else { - panic!("args are not args"); } - } else { - LIST_ANY_TYPE } } - b"bool" => BOOL_TYPE, - // b"cell-path" => SyntaxShape::CellPath, - b"closure" => CLOSURE_TYPE, //FIXME: Closures should have known output types - // b"datetime" => SyntaxShape::DateTime, - // b"directory" => SyntaxShape::Directory, - // b"duration" => SyntaxShape::Duration, - // b"error" => SyntaxShape::Error, - b"float" => FLOAT_TYPE, - // b"filesize" => SyntaxShape::Filesize, - // b"glob" => SyntaxShape::GlobPattern, - b"int" => INT_TYPE, - // _ if bytes.starts_with(b"list") => parse_list_shape(working_set, bytes, span, use_loc), - b"nothing" => NOTHING_TYPE, - b"number" => NUMBER_TYPE, - // b"path" => SyntaxShape::Filepath, - // b"range" => SyntaxShape::Range, - // _ if bytes.starts_with(b"record") => { - // parse_collection_shape(working_set, bytes, span, use_loc) - // } - b"string" => STRING_TYPE, - // _ if bytes.starts_with(b"table") => { - // parse_collection_shape(working_set, bytes, span, use_loc) - // } - _ => { - // if bytes.contains(&b'@') { - // // type with completion - // } else { - UNKNOWN_TYPE - // } + TypeAst::Record { fields, .. } => { + let AstNode::Params(field_nodes) = self.compiler.get_node(*fields) else { + panic!("internal error: record fields aren't Params"); + }; + let mut fields = field_nodes + .iter() + .map(|field| { + let AstNode::Param { name, ty } = self.compiler.get_node(*field) else { + panic!("internal error: record field isn't Param"); + }; + let ty_id = match ty { + Some(ty) => self.typecheck_type(*ty), + None => ANY_TYPE, + }; + (*name, ty_id) + }) + .collect::>(); + // Store fields sorted by name + fields.sort_by_cached_key(|(name, _)| self.compiler.get_span_contents(*name)); + + self.record_types.push(fields); + self.push_type(Type::Record(RecordTypeId(self.record_types.len() - 1))) } - } + }; + + self.set_node_type_id(node_id, type_id); + type_id } /// Add a new type and return its ID. To save space, common types are not pushed and their ID is @@ -916,11 +969,6 @@ impl<'a> Typechecker<'a> { } } - fn set_node_type(&mut self, node_id: NodeId, ty: Type) { - let type_id = self.push_type(ty); - self.node_types[node_id.0] = type_id; - } - fn set_node_type_id(&mut self, node_id: NodeId, type_id: TypeId) { self.node_types[node_id.0] = type_id; } @@ -979,6 +1027,51 @@ impl<'a> Typechecker<'a> { } } + /// Try constraining `sub` to be a subtype of `supe`. Returns whether it was successful + fn constrain_subtype(&mut self, sub: TypeId, supe: TypeId) -> bool { + match (self.types[sub.0], self.types[supe.0]) { + (Type::ExVar(a), Type::ExVar(b)) => a == b, + (Type::ExVar(a), b) => todo!(), + (a, Type::ExVar(b)) => todo!(), + // todo handle lists, unions, and records containing existential variables within + (a, b) => self.is_subtype(a, b), + } + } + + /// Constrain an existential variable to be a subtype of `supe` + fn constrain_ex_sub(&mut self, ex: ExVarId, supe: TypeId) { + match self.types[supe.0] { + Type::ExVar(other) => { + if ex.0 < other.0 { + self.ex_vars[other.0] = ex; + } else { + todo!("add constraint that ex = other"); + } + } + } + } + + /// Constrain an existential variable to be a supertype of `sub` + fn constrain_ex_supe(&mut self, ex: ExVarId, sub: TypeId) { + todo!() + } + + /// Check if `sub` is a subtype of `supe` + fn is_subtype(&self, sub: Type, supe: Type) -> bool { + match (sub, supe) { + (_, Type::Top | Type::Any | Type::Unknown) => true, + (Type::Any | Type::Unknown, _) => true, + (Type::Int | Type::Float | Type::Number, Type::Number) => true, + (Type::List(inner_sub), Type::List(inner_supe)) => { + self.is_subtype(self.types[inner_sub.0], self.types[inner_supe.0]) + } + (_, Type::OneOf(oneof_id)) => self.oneof_types[oneof_id.0] + .iter() + .any(|ty| self.is_subtype(sub, self.types[ty.0])), + (_, _) => sub == supe, + } + } + fn type_to_string(&self, type_id: TypeId) -> String { let ty = &self.types[type_id.0]; @@ -987,6 +1080,7 @@ impl<'a> Typechecker<'a> { Type::Forbidden => "forbidden".to_string(), Type::None => "()".to_string(), Type::Any => "any".to_string(), + Type::Top => "top".to_string(), Type::Number => "number".to_string(), Type::Nothing => "nothing".to_string(), Type::Int => "int".to_string(), @@ -1034,6 +1128,11 @@ impl<'a> Typechecker<'a> { fmt.push('>'); fmt } + Type::Ref(id) => match self.compiler.type_decls[id.0] { + TypeDecl::Param(name) => { + String::from_utf8_lossy(self.compiler.get_span_contents(name)).to_string() + } + }, Type::Error => "error".to_string(), } } @@ -1109,6 +1208,63 @@ impl<'a> Typechecker<'a> { types.insert(*ty); } } + + /// Use this to create any union types, to ensure that the created union type + /// is as simple as possible + fn create_oneof(&mut self, types: HashSet) -> TypeId { + if types.is_empty() { + // TODO return bottom type instead? + return ANY_TYPE; + } + + let mut res = HashSet::::new(); + + let mut flattened = HashSet::new(); + for ty_id in types { + match self.types[ty_id.0] { + Type::OneOf(oneof_id) => { + flattened.extend(&self.oneof_types[oneof_id.0]); + } + _ => { + flattened.insert(ty_id); + } + } + } + + for ty_id in flattened { + if res.contains(&ty_id) { + continue; + } + + let ty = self.types[ty_id.0]; + let mut add = true; + let mut remove = HashSet::new(); + for other_id in res.iter() { + let other = self.types[other_id.0]; + if self.is_subtype(ty, other) { + add = false; + break; + } + if self.is_subtype(other, ty) { + remove.insert(*other_id); + } + } + + if add { + res.insert(ty_id); + for other in remove { + res.remove(&other); + } + } + } + + if res.len() == 1 { + *res.iter().next().unwrap() + } else { + self.oneof_types.push(res); + self.push_type(Type::OneOf(OneOfId(self.oneof_types.len() - 1))) + } + } } /// Check whether two types can perform common numeric operations diff --git a/tests/calls_invalid.nu b/tests/calls_invalid.nu new file mode 100644 index 0000000..f435080 --- /dev/null +++ b/tests/calls_invalid.nu @@ -0,0 +1,3 @@ +def foo [ a: int ] {} +foo 1 2 +foo "string" diff --git a/tests/def_generics.nu b/tests/def_generics.nu new file mode 100644 index 0000000..1e9b850 --- /dev/null +++ b/tests/def_generics.nu @@ -0,0 +1,4 @@ +def f [ x: T ] : nothing -> list { + let z: T = $x + [$z] +}